loader: Update the loader to 1.0.39

Add new extensions for 1.0.39.  Also, updated layers to include
minimal set of functionality for 1.0.39 extensions. Extensions include:
 - VK_KHR_get_physical_device_properties2
 - VK_KHR_shader_draw_parameters
 - VK_EXT_direct_mode_display
 - VK_EXT_display_surface_counter
 - VK_EXT_display_control

Also, redo the LoaderAndLayerIf document.

Change-Id: I10412086da7a798afe832a3892e18f606259b5af
diff --git a/BUILD.md b/BUILD.md
index 3358d13..f504fe8 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -28,7 +28,7 @@
 
 These packages are needed to build this repository:
 ```
-sudo apt-get install git cmake build-essential bison libx11-dev libxcb1-dev libxkbcommon-dev libmirclient-dev libwayland-dev
+sudo apt-get install git cmake build-essential bison libx11-dev libxcb1-dev libxkbcommon-dev libmirclient-dev libwayland-dev libxrandr-dev
 ```
 
 Example debug build (Note that the update\_external\_sources script used below builds external tools into predefined locations. See **Loader and Validation Layer Dependencies** for more information and other options):
diff --git a/include/vulkan/vk_icd.h b/include/vulkan/vk_icd.h
index 7b54fb5..748e552 100644
--- a/include/vulkan/vk_icd.h
+++ b/include/vulkan/vk_icd.h
@@ -25,12 +25,26 @@
 
 #include "vulkan.h"
 
-/*
- * Loader-ICD version negotiation API
- */
-#define CURRENT_LOADER_ICD_INTERFACE_VERSION 3
+// Loader-ICD version negotiation API.  Versions add the following features:
+//   Version 0 - Initial.  Doesn't support vk_icdGetInstanceProcAddr
+//               or vk_icdNegotiateLoaderICDInterfaceVersion.
+//   Version 1 - Add support for vk_icdGetInstanceProcAddr.
+//   Version 2 - Add Loader/ICD Interface version negotiation
+//               via vk_icdNegotiateLoaderICDInterfaceVersion.
+//   Version 3 - Add ICD creation/destruction of KHR_surface objects.
+//   Version 4 - Add unknown physical device extension qyering via
+//               vk_icdGetPhysicalDeviceProcAddr.
+#define CURRENT_LOADER_ICD_INTERFACE_VERSION 4
 #define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0
+#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4
 typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);
+
+// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this
+// flie directly, it won't be found.
+#ifndef PFN_GetPhysicalDeviceProcAddr
+typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
+#endif
+
 /*
  * The ICD must reserve space for a pointer for the loader's dispatch
  * table, at the start of <each object>.
diff --git a/include/vulkan/vk_layer.h b/include/vulkan/vk_layer.h
index 4d0da1a..ebbb198 100644
--- a/include/vulkan/vk_layer.h
+++ b/include/vulkan/vk_layer.h
@@ -35,6 +35,41 @@
 #define VK_LAYER_EXPORT
 #endif
 
+#define MAX_NUM_UNKNOWN_EXTS 250
+
+ // Loader-Layer version negotiation API.  Versions add the following features:
+ //   Versions 0/1 - Initial.  Doesn't support vk_layerGetPhysicalDeviceProcAddr
+ //                  or vk_icdNegotiateLoaderLayerInterfaceVersion.
+ //   Version 2    - Add support for vk_layerGetPhysicalDeviceProcAddr and
+ //                  vk_icdNegotiateLoaderLayerInterfaceVersion.
+#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2
+#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1
+
+ // Internal function
+typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
+
+// Version negotiation values
+typedef enum VkNegotiateLayerStructType {
+    LAYER_NEGOTIATE_UNINTIALIZED = 0,
+    LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
+} VkNegotiateLayerStructType;
+
+// Version negotiation structures
+typedef struct VkNegotiateLayerInterface {
+    VkNegotiateLayerStructType sType;
+    void *pNext;
+    uint32_t loaderLayerInterfaceVersion;
+    PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
+    PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
+    PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
+} VkNegotiateLayerInterface;
+
+// Version negotiation functions
+typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);
+
+// Function prototype for unknown physical device extension command
+typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device, ...);
+
 typedef struct VkLayerDispatchTable_ {
     PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
     PFN_vkDestroyDevice DestroyDevice;
@@ -173,6 +208,14 @@
     PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;
     PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;
     PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;
+    // KHR_maintenance1
+    PFN_vkTrimCommandPoolKHR TrimCommandPoolKHR;
+    // EXT_display_control
+    PFN_vkDisplayPowerControlEXT DisplayPowerControlEXT;
+    PFN_vkRegisterDeviceEventEXT RegisterDeviceEventEXT;
+    PFN_vkRegisterDisplayEventEXT RegisterDisplayEventEXT;
+    PFN_vkGetSwapchainCounterEXT GetSwapchainCounterEXT;
+    // NVX_device_generated_commands
     PFN_vkCmdProcessCommandsNVX CmdProcessCommandsNVX;
     PFN_vkCmdReserveSpaceForCommandsNVX CmdReserveSpaceForCommandsNVX;
     PFN_vkCreateIndirectCommandsLayoutNVX CreateIndirectCommandsLayoutNVX;
@@ -185,6 +228,7 @@
 
 typedef struct VkLayerInstanceDispatchTable_ {
     PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;
     PFN_vkDestroyInstance DestroyInstance;
     PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
     PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
@@ -206,9 +250,6 @@
     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
         GetPhysicalDeviceSurfacePresentModesKHR;
-    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
-    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
-    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
 #ifdef VK_USE_PLATFORM_MIR_KHR
     PFN_vkCreateMirSurfaceKHR CreateMirSurfaceKHR;
     PFN_vkGetPhysicalDeviceMirPresentationSupportKHR
@@ -251,8 +292,37 @@
         GetDisplayPlaneCapabilitiesKHR;
     PFN_vkCreateDisplayPlaneSurfaceKHR
         CreateDisplayPlaneSurfaceKHR;
+    // KHR_get_physical_device_properties2
+    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR;
+    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;
+    PFN_vkGetPhysicalDeviceFormatProperties2KHR
+        GetPhysicalDeviceFormatProperties2KHR;
+    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR
+        GetPhysicalDeviceImageFormatProperties2KHR;
+    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR
+        GetPhysicalDeviceQueueFamilyProperties2KHR;
+    PFN_vkGetPhysicalDeviceMemoryProperties2KHR
+        GetPhysicalDeviceMemoryProperties2KHR;
+    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR
+        GetPhysicalDeviceSparseImageFormatProperties2KHR;
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // EXT_acquire_xlib_display
+    PFN_vkAcquireXlibDisplayEXT AcquireXlibDisplayEXT;
+    PFN_vkGetRandROutputDisplayEXT GetRandROutputDisplayEXT;
+#endif
+    // EXT_debug_report
+    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
+    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+    // EXT_direct_mode_display
+    PFN_vkReleaseDisplayEXT ReleaseDisplayEXT;
+    // EXT_display_surface_counter
+    PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT
+        GetPhysicalDeviceSurfaceCapabilities2EXT;
+    // NV_external_memory_capabilities
     PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV
         GetPhysicalDeviceExternalImageFormatPropertiesNV;
+    // NVX_device_generated_commands (phys dev commands)
     PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX
         GetPhysicalDeviceGeneratedCommandsPropertiesNVX;
 } VkLayerInstanceDispatchTable;
@@ -273,6 +343,7 @@
 typedef struct VkLayerInstanceLink_ {
     struct VkLayerInstanceLink_ *pNext;
     PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
+    PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr;
 } VkLayerInstanceLink;
 
 /*
diff --git a/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
index f24a0a2..81dedf7 100644
--- a/include/vulkan/vulkan.h
+++ b/include/vulkan/vulkan.h
@@ -6,7 +6,7 @@
 #endif
 
 /*
-** Copyright (c) 2015-2016 The Khronos Group Inc.
+** Copyright (c) 2015-2017 The Khronos Group Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 38
+#define VK_HEADER_VERSION 39
 
 
 #define VK_NULL_HANDLE 0
@@ -145,6 +145,7 @@
     VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
     VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
     VK_ERROR_INVALID_SHADER_NV = -1000012000,
+    VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000,
     VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
     VK_RESULT_END_RANGE = VK_INCOMPLETE,
     VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
@@ -225,13 +226,28 @@
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
     VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
     VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
+    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
     VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+    VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
     VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
     VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
     VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
     VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
     VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
     VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
+    VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
+    VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
+    VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
+    VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
     VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
     VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
     VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
@@ -840,6 +856,8 @@
     VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
+    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
+    VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
     VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkFormatFeatureFlagBits;
 typedef VkFlags VkFormatFeatureFlags;
@@ -863,6 +881,7 @@
     VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
     VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,
     VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,
+    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
     VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkImageCreateFlagBits;
 typedef VkFlags VkImageCreateFlags;
@@ -3206,6 +3225,18 @@
 
 typedef enum VkColorSpaceKHR {
     VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
+    VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001,
+    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002,
+    VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003,
+    VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004,
+    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005,
+    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006,
+    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007,
+    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008,
+    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009,
+    VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010,
+    VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
+    VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -3741,6 +3772,136 @@
 #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
 
 
+#define VK_KHR_get_physical_device_properties2 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+
+typedef struct VkPhysicalDeviceFeatures2KHR {
+    VkStructureType             sType;
+    void*                       pNext;
+    VkPhysicalDeviceFeatures    features;
+} VkPhysicalDeviceFeatures2KHR;
+
+typedef struct VkPhysicalDeviceProperties2KHR {
+    VkStructureType               sType;
+    void*                         pNext;
+    VkPhysicalDeviceProperties    properties;
+} VkPhysicalDeviceProperties2KHR;
+
+typedef struct VkFormatProperties2KHR {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkFormatProperties    formatProperties;
+} VkFormatProperties2KHR;
+
+typedef struct VkImageFormatProperties2KHR {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkImageFormatProperties    imageFormatProperties;
+} VkImageFormatProperties2KHR;
+
+typedef struct VkPhysicalDeviceImageFormatInfo2KHR {
+    VkStructureType       sType;
+    const void*           pNext;
+    VkFormat              format;
+    VkImageType           type;
+    VkImageTiling         tiling;
+    VkImageUsageFlags     usage;
+    VkImageCreateFlags    flags;
+} VkPhysicalDeviceImageFormatInfo2KHR;
+
+typedef struct VkQueueFamilyProperties2KHR {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkQueueFamilyProperties    queueFamilyProperties;
+} VkQueueFamilyProperties2KHR;
+
+typedef struct VkPhysicalDeviceMemoryProperties2KHR {
+    VkStructureType                     sType;
+    void*                               pNext;
+    VkPhysicalDeviceMemoryProperties    memoryProperties;
+} VkPhysicalDeviceMemoryProperties2KHR;
+
+typedef struct VkSparseImageFormatProperties2KHR {
+    VkStructureType                  sType;
+    void*                            pNext;
+    VkSparseImageFormatProperties    properties;
+} VkSparseImageFormatProperties2KHR;
+
+typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkFormat                 format;
+    VkImageType              type;
+    VkSampleCountFlagBits    samples;
+    VkImageUsageFlags        usage;
+    VkImageTiling            tiling;
+} VkPhysicalDeviceSparseImageFormatInfo2KHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures2KHR*               pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties2KHR*             pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties2KHR*                     pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2KHR*  pImageFormatInfo,
+    VkImageFormatProperties2KHR*                pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2KHR*                pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties2KHR*       pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
+    uint32_t*                                   pPropertyCount,
+    VkSparseImageFormatProperties2KHR*          pProperties);
+#endif
+
+#define VK_KHR_shader_draw_parameters 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
+
+
+#define VK_KHR_maintenance1 1
+#define VK_KHR_MAINTENANCE1_SPEC_VERSION  1
+#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
+
+typedef VkFlags VkCommandPoolTrimFlagsKHR;
+
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    VkCommandPoolTrimFlagsKHR                   flags);
+#endif
+
 #define VK_EXT_debug_report 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
 
@@ -4167,6 +4328,42 @@
 
 
 
+#ifdef VK_USE_PLATFORM_VI_NN
+#define VK_NN_vi_surface 1
+#define VK_NN_VI_SURFACE_SPEC_VERSION     1
+#define VK_NN_VI_SURFACE_EXTENSION_NAME   "VK_NN_vi_surface"
+
+typedef VkFlags VkViSurfaceCreateFlagsNN;
+
+typedef struct VkViSurfaceCreateInfoNN {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkViSurfaceCreateFlagsNN    flags;
+    void*                       window;
+} VkViSurfaceCreateInfoNN;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
+    VkInstance                                  instance,
+    const VkViSurfaceCreateInfoNN*              pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSurfaceKHR*                               pSurface);
+#endif
+#endif /* VK_USE_PLATFORM_VI_NN */
+
+#define VK_EXT_shader_subgroup_ballot 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
+
+
+#define VK_EXT_shader_subgroup_vote 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
+
+
 #define VK_NVX_device_generated_commands 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
@@ -4322,6 +4519,7 @@
     VkObjectEntryTypeNVX          type;
     VkObjectEntryUsageFlagsNVX    flags;
     VkBuffer                      buffer;
+    VkIndexType                   indexType;
 } VkObjectTableIndexBufferEntryNVX;
 
 typedef struct VkObjectTablePushConstantEntryNVX {
@@ -4393,6 +4591,171 @@
     VkDeviceGeneratedCommandsLimitsNVX*         pLimits);
 #endif
 
+#define VK_EXT_direct_mode_display 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
+
+typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT(
+    VkPhysicalDevice                            physicalDevice,
+    VkDisplayKHR                                display);
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+#define VK_EXT_acquire_xlib_display 1
+#include <X11/extensions/Xrandr.h>
+
+#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
+#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
+
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);
+typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
+    VkPhysicalDevice                            physicalDevice,
+    Display*                                    dpy,
+    VkDisplayKHR                                display);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(
+    VkPhysicalDevice                            physicalDevice,
+    Display*                                    dpy,
+    RROutput                                    rrOutput,
+    VkDisplayKHR*                               pDisplay);
+#endif
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
+#define VK_EXT_display_surface_counter 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
+
+
+typedef enum VkSurfaceCounterFlagBitsEXT {
+    VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
+    VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSurfaceCounterFlagBitsEXT;
+typedef VkFlags VkSurfaceCounterFlagsEXT;
+
+typedef struct VkSurfaceCapabilities2EXT {
+    VkStructureType                  sType;
+    void*                            pNext;
+    uint32_t                         minImageCount;
+    uint32_t                         maxImageCount;
+    VkExtent2D                       currentExtent;
+    VkExtent2D                       minImageExtent;
+    VkExtent2D                       maxImageExtent;
+    uint32_t                         maxImageArrayLayers;
+    VkSurfaceTransformFlagsKHR       supportedTransforms;
+    VkSurfaceTransformFlagBitsKHR    currentTransform;
+    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;
+    VkImageUsageFlags                supportedUsageFlags;
+    VkSurfaceCounterFlagsEXT         supportedSurfaceCounters;
+} VkSurfaceCapabilities2EXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities);
+#endif
+
+#define VK_EXT_display_control 1
+#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control"
+
+
+typedef enum VkDisplayPowerStateEXT {
+    VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
+    VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
+    VK_DISPLAY_POWER_STATE_ON_EXT = 2,
+    VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT,
+    VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT,
+    VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1),
+    VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayPowerStateEXT;
+
+typedef enum VkDeviceEventTypeEXT {
+    VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
+    VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+    VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+    VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1),
+    VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDeviceEventTypeEXT;
+
+typedef enum VkDisplayEventTypeEXT {
+    VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
+    VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+    VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+    VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1),
+    VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayEventTypeEXT;
+
+typedef struct VkDisplayPowerInfoEXT {
+    VkStructureType           sType;
+    const void*               pNext;
+    VkDisplayPowerStateEXT    powerState;
+} VkDisplayPowerInfoEXT;
+
+typedef struct VkDeviceEventInfoEXT {
+    VkStructureType         sType;
+    const void*             pNext;
+    VkDeviceEventTypeEXT    deviceEvent;
+} VkDeviceEventInfoEXT;
+
+typedef struct VkDisplayEventInfoEXT {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkDisplayEventTypeEXT    displayEvent;
+} VkDisplayEventInfoEXT;
+
+typedef struct VkSwapchainCounterCreateInfoEXT {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkSurfaceCounterFlagsEXT    surfaceCounters;
+} VkSwapchainCounterCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT(
+    VkDevice                                    device,
+    VkDisplayKHR                                display,
+    const VkDisplayPowerInfoEXT*                pDisplayPowerInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT(
+    VkDevice                                    device,
+    const VkDeviceEventInfoEXT*                 pDeviceEventInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFence*                                    pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT(
+    VkDevice                                    device,
+    VkDisplayKHR                                display,
+    const VkDisplayEventInfoEXT*                pDisplayEventInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFence*                                    pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    VkSurfaceCounterFlagBitsEXT                 counter,
+    uint64_t*                                   pCounterValue);
+#endif
+
+#define VK_EXT_swapchain_colorspace 1
+#define VK_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1
+#define VK_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/vulkan/vulkan.hpp b/include/vulkan/vulkan.hpp
index a239dd1..dd34651 100644
--- a/include/vulkan/vulkan.hpp
+++ b/include/vulkan/vulkan.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2017 The Khronos Group Inc.
 // 
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and/or associated documentation files (the
@@ -41,7 +41,7 @@
 # include <vector>
 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
 
-static_assert( VK_HEADER_VERSION ==  38 , "Wrong VK_HEADER_VERSION!" );
+static_assert( VK_HEADER_VERSION ==  39 , "Wrong VK_HEADER_VERSION!" );
 
 // 32-bit vulkan is not typesafe for handles, so don't allow copy constructors on this platform by default.
 // To enable this feature on 32-bit platforms please define VULKAN_HPP_TYPESAFE_CONVERSION
@@ -343,7 +343,8 @@
     eErrorOutOfDateKHR = VK_ERROR_OUT_OF_DATE_KHR,
     eErrorIncompatibleDisplayKHR = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR,
     eErrorValidationFailedEXT = VK_ERROR_VALIDATION_FAILED_EXT,
-    eErrorInvalidShaderNV = VK_ERROR_INVALID_SHADER_NV
+    eErrorInvalidShaderNV = VK_ERROR_INVALID_SHADER_NV,
+    eErrorOutOfPoolMemoryKHR = VK_ERROR_OUT_OF_POOL_MEMORY_KHR
   };
 
   VULKAN_HPP_INLINE std::string to_string(Result value)
@@ -375,6 +376,7 @@
     case Result::eErrorIncompatibleDisplayKHR: return "ErrorIncompatibleDisplayKHR";
     case Result::eErrorValidationFailedEXT: return "ErrorValidationFailedEXT";
     case Result::eErrorInvalidShaderNV: return "ErrorInvalidShaderNV";
+    case Result::eErrorOutOfPoolMemoryKHR: return "ErrorOutOfPoolMemoryKHR";
     default: return "invalid";
     }
   }
@@ -886,6 +888,21 @@
   }
 #endif /*VK_USE_PLATFORM_MIR_KHR*/
 
+#ifdef VK_USE_PLATFORM_VI_NN
+  enum class ViSurfaceCreateFlagBitsNN
+  {
+  };
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
+#ifdef VK_USE_PLATFORM_VI_NN
+  using ViSurfaceCreateFlagsNN = Flags<ViSurfaceCreateFlagBitsNN, VkViSurfaceCreateFlagsNN>;
+
+  VULKAN_HPP_INLINE ViSurfaceCreateFlagsNN operator|( ViSurfaceCreateFlagBitsNN bit0, ViSurfaceCreateFlagBitsNN bit1 )
+  {
+    return ViSurfaceCreateFlagsNN( bit0 ) | bit1;
+  }
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
   enum class WaylandSurfaceCreateFlagBitsKHR
   {
@@ -946,6 +963,17 @@
   }
 #endif /*VK_USE_PLATFORM_XCB_KHR*/
 
+  enum class CommandPoolTrimFlagBitsKHR
+  {
+  };
+
+  using CommandPoolTrimFlagsKHR = Flags<CommandPoolTrimFlagBitsKHR, VkCommandPoolTrimFlagsKHR>;
+
+  VULKAN_HPP_INLINE CommandPoolTrimFlagsKHR operator|( CommandPoolTrimFlagBitsKHR bit0, CommandPoolTrimFlagBitsKHR bit1 )
+  {
+    return CommandPoolTrimFlagsKHR( bit0 ) | bit1;
+  }
+
   class DeviceMemory
   {
   public:
@@ -5523,13 +5551,28 @@
     eImportMemoryWin32HandleInfoNV = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV,
     eExportMemoryWin32HandleInfoNV = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV,
     eWin32KeyedMutexAcquireReleaseInfoNV = VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV,
+    ePhysicalDeviceFeatures2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
+    ePhysicalDeviceProperties2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+    eFormatProperties2KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR,
+    eImageFormatProperties2KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR,
+    ePhysicalDeviceImageFormatInfo2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR,
+    eQueueFamilyProperties2KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR,
+    ePhysicalDeviceMemoryProperties2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR,
+    eSparseImageFormatProperties2KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR,
+    ePhysicalDeviceSparseImageFormatInfo2KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR,
     eValidationFlagsEXT = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT,
+    eViSurfaceCreateInfoNN = VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN,
     eObjectTableCreateInfoNVX = VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX,
     eIndirectCommandsLayoutCreateInfoNVX = VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX,
     eCmdProcessCommandsInfoNVX = VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX,
     eCmdReserveSpaceForCommandsInfoNVX = VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX,
     eDeviceGeneratedCommandsLimitsNVX = VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX,
-    eDeviceGeneratedCommandsFeaturesNVX = VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX
+    eDeviceGeneratedCommandsFeaturesNVX = VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX,
+    eSurfaceCapabilities2EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT,
+    eDisplayPowerInfoEXT = VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT,
+    eDeviceEventInfoEXT = VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT,
+    eDisplayEventInfoEXT = VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT,
+    eSwapchainCounterCreateInfoEXT = VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT
   };
 
   struct ApplicationInfo
@@ -8300,6 +8343,81 @@
   static_assert( sizeof( MirSurfaceCreateInfoKHR ) == sizeof( VkMirSurfaceCreateInfoKHR ), "struct and wrapper have different size!" );
 #endif /*VK_USE_PLATFORM_MIR_KHR*/
 
+#ifdef VK_USE_PLATFORM_VI_NN
+  struct ViSurfaceCreateInfoNN
+  {
+    ViSurfaceCreateInfoNN( ViSurfaceCreateFlagsNN flags_ = ViSurfaceCreateFlagsNN(), void* window_ = nullptr )
+      : sType( StructureType::eViSurfaceCreateInfoNN )
+      , pNext( nullptr )
+      , flags( flags_ )
+      , window( window_ )
+    {
+    }
+
+    ViSurfaceCreateInfoNN( VkViSurfaceCreateInfoNN const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(ViSurfaceCreateInfoNN) );
+    }
+
+    ViSurfaceCreateInfoNN& operator=( VkViSurfaceCreateInfoNN const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(ViSurfaceCreateInfoNN) );
+      return *this;
+    }
+
+    ViSurfaceCreateInfoNN& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    ViSurfaceCreateInfoNN& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    ViSurfaceCreateInfoNN& setFlags( ViSurfaceCreateFlagsNN flags_ )
+    {
+      flags = flags_;
+      return *this;
+    }
+
+    ViSurfaceCreateInfoNN& setWindow( void* window_ )
+    {
+      window = window_;
+      return *this;
+    }
+
+    operator const VkViSurfaceCreateInfoNN&() const
+    {
+      return *reinterpret_cast<const VkViSurfaceCreateInfoNN*>(this);
+    }
+
+    bool operator==( ViSurfaceCreateInfoNN const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( flags == rhs.flags )
+          && ( window == rhs.window );
+    }
+
+    bool operator!=( ViSurfaceCreateInfoNN const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    ViSurfaceCreateFlagsNN flags;
+    void* window;
+  };
+  static_assert( sizeof( ViSurfaceCreateInfoNN ) == sizeof( VkViSurfaceCreateInfoNN ), "struct and wrapper have different size!" );
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
   struct WaylandSurfaceCreateInfoKHR
   {
@@ -9351,6 +9469,70 @@
   };
   static_assert( sizeof( CmdReserveSpaceForCommandsInfoNVX ) == sizeof( VkCmdReserveSpaceForCommandsInfoNVX ), "struct and wrapper have different size!" );
 
+  struct PhysicalDeviceFeatures2KHR
+  {
+    PhysicalDeviceFeatures2KHR( PhysicalDeviceFeatures features_ = PhysicalDeviceFeatures() )
+      : sType( StructureType::ePhysicalDeviceFeatures2KHR )
+      , pNext( nullptr )
+      , features( features_ )
+    {
+    }
+
+    PhysicalDeviceFeatures2KHR( VkPhysicalDeviceFeatures2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures2KHR) );
+    }
+
+    PhysicalDeviceFeatures2KHR& operator=( VkPhysicalDeviceFeatures2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceFeatures2KHR) );
+      return *this;
+    }
+
+    PhysicalDeviceFeatures2KHR& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    PhysicalDeviceFeatures2KHR& setPNext( void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    PhysicalDeviceFeatures2KHR& setFeatures( PhysicalDeviceFeatures features_ )
+    {
+      features = features_;
+      return *this;
+    }
+
+    operator const VkPhysicalDeviceFeatures2KHR&() const
+    {
+      return *reinterpret_cast<const VkPhysicalDeviceFeatures2KHR*>(this);
+    }
+
+    bool operator==( PhysicalDeviceFeatures2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( features == rhs.features );
+    }
+
+    bool operator!=( PhysicalDeviceFeatures2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    PhysicalDeviceFeatures features;
+  };
+  static_assert( sizeof( PhysicalDeviceFeatures2KHR ) == sizeof( VkPhysicalDeviceFeatures2KHR ), "struct and wrapper have different size!" );
+
   enum class SubpassContents
   {
     eInline = VK_SUBPASS_CONTENTS_INLINE,
@@ -9616,6 +9798,34 @@
   };
   static_assert( sizeof( QueueFamilyProperties ) == sizeof( VkQueueFamilyProperties ), "struct and wrapper have different size!" );
 
+  struct QueueFamilyProperties2KHR
+  {
+    operator const VkQueueFamilyProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkQueueFamilyProperties2KHR*>(this);
+    }
+
+    bool operator==( QueueFamilyProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( queueFamilyProperties == rhs.queueFamilyProperties );
+    }
+
+    bool operator!=( QueueFamilyProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    QueueFamilyProperties queueFamilyProperties;
+  };
+  static_assert( sizeof( QueueFamilyProperties2KHR ) == sizeof( VkQueueFamilyProperties2KHR ), "struct and wrapper have different size!" );
+
   enum class MemoryPropertyFlagBits
   {
     eDeviceLocal = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@@ -9743,6 +9953,34 @@
   };
   static_assert( sizeof( PhysicalDeviceMemoryProperties ) == sizeof( VkPhysicalDeviceMemoryProperties ), "struct and wrapper have different size!" );
 
+  struct PhysicalDeviceMemoryProperties2KHR
+  {
+    operator const VkPhysicalDeviceMemoryProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkPhysicalDeviceMemoryProperties2KHR*>(this);
+    }
+
+    bool operator==( PhysicalDeviceMemoryProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( memoryProperties == rhs.memoryProperties );
+    }
+
+    bool operator!=( PhysicalDeviceMemoryProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    PhysicalDeviceMemoryProperties memoryProperties;
+  };
+  static_assert( sizeof( PhysicalDeviceMemoryProperties2KHR ) == sizeof( VkPhysicalDeviceMemoryProperties2KHR ), "struct and wrapper have different size!" );
+
   enum class AccessFlagBits
   {
     eIndirectCommandRead = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
@@ -10638,7 +10876,8 @@
     eSparseResidency = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT,
     eSparseAliased = VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,
     eMutableFormat = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
-    eCubeCompatible = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
+    eCubeCompatible = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
+    e2DArrayCompatibleKHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR
   };
 
   using ImageCreateFlags = Flags<ImageCreateFlagBits, VkImageCreateFlags>;
@@ -10657,10 +10896,110 @@
   {
     enum
     {
-      allFlags = VkFlags(ImageCreateFlagBits::eSparseBinding) | VkFlags(ImageCreateFlagBits::eSparseResidency) | VkFlags(ImageCreateFlagBits::eSparseAliased) | VkFlags(ImageCreateFlagBits::eMutableFormat) | VkFlags(ImageCreateFlagBits::eCubeCompatible)
+      allFlags = VkFlags(ImageCreateFlagBits::eSparseBinding) | VkFlags(ImageCreateFlagBits::eSparseResidency) | VkFlags(ImageCreateFlagBits::eSparseAliased) | VkFlags(ImageCreateFlagBits::eMutableFormat) | VkFlags(ImageCreateFlagBits::eCubeCompatible) | VkFlags(ImageCreateFlagBits::e2DArrayCompatibleKHR)
     };
   };
 
+  struct PhysicalDeviceImageFormatInfo2KHR
+  {
+    PhysicalDeviceImageFormatInfo2KHR( Format format_ = Format::eUndefined, ImageType type_ = ImageType::e1D, ImageTiling tiling_ = ImageTiling::eOptimal, ImageUsageFlags usage_ = ImageUsageFlags(), ImageCreateFlags flags_ = ImageCreateFlags() )
+      : sType( StructureType::ePhysicalDeviceImageFormatInfo2KHR )
+      , pNext( nullptr )
+      , format( format_ )
+      , type( type_ )
+      , tiling( tiling_ )
+      , usage( usage_ )
+      , flags( flags_ )
+    {
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR( VkPhysicalDeviceImageFormatInfo2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceImageFormatInfo2KHR) );
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& operator=( VkPhysicalDeviceImageFormatInfo2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceImageFormatInfo2KHR) );
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setFormat( Format format_ )
+    {
+      format = format_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setType( ImageType type_ )
+    {
+      type = type_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setTiling( ImageTiling tiling_ )
+    {
+      tiling = tiling_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setUsage( ImageUsageFlags usage_ )
+    {
+      usage = usage_;
+      return *this;
+    }
+
+    PhysicalDeviceImageFormatInfo2KHR& setFlags( ImageCreateFlags flags_ )
+    {
+      flags = flags_;
+      return *this;
+    }
+
+    operator const VkPhysicalDeviceImageFormatInfo2KHR&() const
+    {
+      return *reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>(this);
+    }
+
+    bool operator==( PhysicalDeviceImageFormatInfo2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( format == rhs.format )
+          && ( type == rhs.type )
+          && ( tiling == rhs.tiling )
+          && ( usage == rhs.usage )
+          && ( flags == rhs.flags );
+    }
+
+    bool operator!=( PhysicalDeviceImageFormatInfo2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    Format format;
+    ImageType type;
+    ImageTiling tiling;
+    ImageUsageFlags usage;
+    ImageCreateFlags flags;
+  };
+  static_assert( sizeof( PhysicalDeviceImageFormatInfo2KHR ) == sizeof( VkPhysicalDeviceImageFormatInfo2KHR ), "struct and wrapper have different size!" );
+
   enum class PipelineCreateFlagBits
   {
     eDisableOptimization = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
@@ -11135,7 +11474,9 @@
     eBlitSrc = VK_FORMAT_FEATURE_BLIT_SRC_BIT,
     eBlitDst = VK_FORMAT_FEATURE_BLIT_DST_BIT,
     eSampledImageFilterLinear = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,
-    eSampledImageFilterCubicIMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG
+    eSampledImageFilterCubicIMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,
+    eTransferSrcKHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR,
+    eTransferDstKHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR
   };
 
   using FormatFeatureFlags = Flags<FormatFeatureFlagBits, VkFormatFeatureFlags>;
@@ -11154,7 +11495,7 @@
   {
     enum
     {
-      allFlags = VkFlags(FormatFeatureFlagBits::eSampledImage) | VkFlags(FormatFeatureFlagBits::eStorageImage) | VkFlags(FormatFeatureFlagBits::eStorageImageAtomic) | VkFlags(FormatFeatureFlagBits::eUniformTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBufferAtomic) | VkFlags(FormatFeatureFlagBits::eVertexBuffer) | VkFlags(FormatFeatureFlagBits::eColorAttachment) | VkFlags(FormatFeatureFlagBits::eColorAttachmentBlend) | VkFlags(FormatFeatureFlagBits::eDepthStencilAttachment) | VkFlags(FormatFeatureFlagBits::eBlitSrc) | VkFlags(FormatFeatureFlagBits::eBlitDst) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterLinear) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterCubicIMG)
+      allFlags = VkFlags(FormatFeatureFlagBits::eSampledImage) | VkFlags(FormatFeatureFlagBits::eStorageImage) | VkFlags(FormatFeatureFlagBits::eStorageImageAtomic) | VkFlags(FormatFeatureFlagBits::eUniformTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBuffer) | VkFlags(FormatFeatureFlagBits::eStorageTexelBufferAtomic) | VkFlags(FormatFeatureFlagBits::eVertexBuffer) | VkFlags(FormatFeatureFlagBits::eColorAttachment) | VkFlags(FormatFeatureFlagBits::eColorAttachmentBlend) | VkFlags(FormatFeatureFlagBits::eDepthStencilAttachment) | VkFlags(FormatFeatureFlagBits::eBlitSrc) | VkFlags(FormatFeatureFlagBits::eBlitDst) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterLinear) | VkFlags(FormatFeatureFlagBits::eSampledImageFilterCubicIMG) | VkFlags(FormatFeatureFlagBits::eTransferSrcKHR) | VkFlags(FormatFeatureFlagBits::eTransferDstKHR)
     };
   };
 
@@ -11183,6 +11524,34 @@
   };
   static_assert( sizeof( FormatProperties ) == sizeof( VkFormatProperties ), "struct and wrapper have different size!" );
 
+  struct FormatProperties2KHR
+  {
+    operator const VkFormatProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkFormatProperties2KHR*>(this);
+    }
+
+    bool operator==( FormatProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( formatProperties == rhs.formatProperties );
+    }
+
+    bool operator!=( FormatProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    FormatProperties formatProperties;
+  };
+  static_assert( sizeof( FormatProperties2KHR ) == sizeof( VkFormatProperties2KHR ), "struct and wrapper have different size!" );
+
   enum class QueryControlFlagBits
   {
     ePrecise = VK_QUERY_CONTROL_PRECISE_BIT
@@ -12491,6 +12860,34 @@
   };
   static_assert( sizeof( SparseImageMemoryRequirements ) == sizeof( VkSparseImageMemoryRequirements ), "struct and wrapper have different size!" );
 
+  struct SparseImageFormatProperties2KHR
+  {
+    operator const VkSparseImageFormatProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkSparseImageFormatProperties2KHR*>(this);
+    }
+
+    bool operator==( SparseImageFormatProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( properties == rhs.properties );
+    }
+
+    bool operator!=( SparseImageFormatProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    SparseImageFormatProperties properties;
+  };
+  static_assert( sizeof( SparseImageFormatProperties2KHR ) == sizeof( VkSparseImageFormatProperties2KHR ), "struct and wrapper have different size!" );
+
   enum class SparseMemoryBindFlagBits
   {
     eMetadata = VK_SPARSE_MEMORY_BIND_METADATA_BIT
@@ -14028,6 +14425,162 @@
   };
   static_assert( sizeof( PhysicalDeviceProperties ) == sizeof( VkPhysicalDeviceProperties ), "struct and wrapper have different size!" );
 
+  struct PhysicalDeviceProperties2KHR
+  {
+    operator const VkPhysicalDeviceProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkPhysicalDeviceProperties2KHR*>(this);
+    }
+
+    bool operator==( PhysicalDeviceProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( properties == rhs.properties );
+    }
+
+    bool operator!=( PhysicalDeviceProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    PhysicalDeviceProperties properties;
+  };
+  static_assert( sizeof( PhysicalDeviceProperties2KHR ) == sizeof( VkPhysicalDeviceProperties2KHR ), "struct and wrapper have different size!" );
+
+  struct ImageFormatProperties2KHR
+  {
+    operator const VkImageFormatProperties2KHR&() const
+    {
+      return *reinterpret_cast<const VkImageFormatProperties2KHR*>(this);
+    }
+
+    bool operator==( ImageFormatProperties2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( imageFormatProperties == rhs.imageFormatProperties );
+    }
+
+    bool operator!=( ImageFormatProperties2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    ImageFormatProperties imageFormatProperties;
+  };
+  static_assert( sizeof( ImageFormatProperties2KHR ) == sizeof( VkImageFormatProperties2KHR ), "struct and wrapper have different size!" );
+
+  struct PhysicalDeviceSparseImageFormatInfo2KHR
+  {
+    PhysicalDeviceSparseImageFormatInfo2KHR( Format format_ = Format::eUndefined, ImageType type_ = ImageType::e1D, SampleCountFlagBits samples_ = SampleCountFlagBits::e1, ImageUsageFlags usage_ = ImageUsageFlags(), ImageTiling tiling_ = ImageTiling::eOptimal )
+      : sType( StructureType::ePhysicalDeviceSparseImageFormatInfo2KHR )
+      , pNext( nullptr )
+      , format( format_ )
+      , type( type_ )
+      , samples( samples_ )
+      , usage( usage_ )
+      , tiling( tiling_ )
+    {
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR( VkPhysicalDeviceSparseImageFormatInfo2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceSparseImageFormatInfo2KHR) );
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& operator=( VkPhysicalDeviceSparseImageFormatInfo2KHR const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(PhysicalDeviceSparseImageFormatInfo2KHR) );
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setFormat( Format format_ )
+    {
+      format = format_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setType( ImageType type_ )
+    {
+      type = type_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setSamples( SampleCountFlagBits samples_ )
+    {
+      samples = samples_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setUsage( ImageUsageFlags usage_ )
+    {
+      usage = usage_;
+      return *this;
+    }
+
+    PhysicalDeviceSparseImageFormatInfo2KHR& setTiling( ImageTiling tiling_ )
+    {
+      tiling = tiling_;
+      return *this;
+    }
+
+    operator const VkPhysicalDeviceSparseImageFormatInfo2KHR&() const
+    {
+      return *reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>(this);
+    }
+
+    bool operator==( PhysicalDeviceSparseImageFormatInfo2KHR const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( format == rhs.format )
+          && ( type == rhs.type )
+          && ( samples == rhs.samples )
+          && ( usage == rhs.usage )
+          && ( tiling == rhs.tiling );
+    }
+
+    bool operator!=( PhysicalDeviceSparseImageFormatInfo2KHR const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    Format format;
+    ImageType type;
+    SampleCountFlagBits samples;
+    ImageUsageFlags usage;
+    ImageTiling tiling;
+  };
+  static_assert( sizeof( PhysicalDeviceSparseImageFormatInfo2KHR ) == sizeof( VkPhysicalDeviceSparseImageFormatInfo2KHR ), "struct and wrapper have different size!" );
+
   enum class AttachmentDescriptionFlagBits
   {
     eMayAlias = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT
@@ -14561,7 +15114,19 @@
 
   enum class ColorSpaceKHR
   {
-    eSrgbNonlinear = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
+    eSrgbNonlinear = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+    eDisplayP3LinearEXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT,
+    eDisplayP3NonlinearEXT = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,
+    eScrgbLinearEXT = VK_COLOR_SPACE_SCRGB_LINEAR_EXT,
+    eScrgbNonlinearEXT = VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT,
+    eDciP3LinearEXT = VK_COLOR_SPACE_DCI_P3_LINEAR_EXT,
+    eDciP3NonlinearEXT = VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT,
+    eBt709LinearEXT = VK_COLOR_SPACE_BT709_LINEAR_EXT,
+    eBt709NonlinearEXT = VK_COLOR_SPACE_BT709_NONLINEAR_EXT,
+    eBt2020LinearEXT = VK_COLOR_SPACE_BT2020_LINEAR_EXT,
+    eBt2020NonlinearEXT = VK_COLOR_SPACE_BT2020_NONLINEAR_EXT,
+    eAdobergbLinearEXT = VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT,
+    eAdobergbNonlinearEXT = VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT
   };
 
   struct SurfaceFormatKHR
@@ -16559,10 +17124,11 @@
 
   struct ObjectTableIndexBufferEntryNVX
   {
-    ObjectTableIndexBufferEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), Buffer buffer_ = Buffer() )
+    ObjectTableIndexBufferEntryNVX( ObjectEntryTypeNVX type_ = ObjectEntryTypeNVX::eVkObjectEntryDescriptorSet, ObjectEntryUsageFlagsNVX flags_ = ObjectEntryUsageFlagsNVX(), Buffer buffer_ = Buffer(), IndexType indexType_ = IndexType::eUint16 )
       : type( type_ )
       , flags( flags_ )
       , buffer( buffer_ )
+      , indexType( indexType_ )
     {
     }
 
@@ -16595,6 +17161,12 @@
       return *this;
     }
 
+    ObjectTableIndexBufferEntryNVX& setIndexType( IndexType indexType_ )
+    {
+      indexType = indexType_;
+      return *this;
+    }
+
     operator const VkObjectTableIndexBufferEntryNVX&() const
     {
       return *reinterpret_cast<const VkObjectTableIndexBufferEntryNVX*>(this);
@@ -16604,7 +17176,8 @@
     {
       return ( type == rhs.type )
           && ( flags == rhs.flags )
-          && ( buffer == rhs.buffer );
+          && ( buffer == rhs.buffer )
+          && ( indexType == rhs.indexType );
     }
 
     bool operator!=( ObjectTableIndexBufferEntryNVX const& rhs ) const
@@ -16615,6 +17188,7 @@
     ObjectEntryTypeNVX type;
     ObjectEntryUsageFlagsNVX flags;
     Buffer buffer;
+    IndexType indexType;
   };
   static_assert( sizeof( ObjectTableIndexBufferEntryNVX ) == sizeof( VkObjectTableIndexBufferEntryNVX ), "struct and wrapper have different size!" );
 
@@ -16688,6 +17262,352 @@
   };
   static_assert( sizeof( ObjectTablePushConstantEntryNVX ) == sizeof( VkObjectTablePushConstantEntryNVX ), "struct and wrapper have different size!" );
 
+  enum class SurfaceCounterFlagBitsEXT
+  {
+    eVblankExt = VK_SURFACE_COUNTER_VBLANK_EXT
+  };
+
+  using SurfaceCounterFlagsEXT = Flags<SurfaceCounterFlagBitsEXT, VkSurfaceCounterFlagsEXT>;
+
+  VULKAN_HPP_INLINE SurfaceCounterFlagsEXT operator|( SurfaceCounterFlagBitsEXT bit0, SurfaceCounterFlagBitsEXT bit1 )
+  {
+    return SurfaceCounterFlagsEXT( bit0 ) | bit1;
+  }
+
+  VULKAN_HPP_INLINE SurfaceCounterFlagsEXT operator~( SurfaceCounterFlagBitsEXT bits )
+  {
+    return ~( SurfaceCounterFlagsEXT( bits ) );
+  }
+
+  template <> struct FlagTraits<SurfaceCounterFlagBitsEXT>
+  {
+    enum
+    {
+      allFlags = VkFlags(SurfaceCounterFlagBitsEXT::eVblankExt)
+    };
+  };
+
+  struct SurfaceCapabilities2EXT
+  {
+    operator const VkSurfaceCapabilities2EXT&() const
+    {
+      return *reinterpret_cast<const VkSurfaceCapabilities2EXT*>(this);
+    }
+
+    bool operator==( SurfaceCapabilities2EXT const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( minImageCount == rhs.minImageCount )
+          && ( maxImageCount == rhs.maxImageCount )
+          && ( currentExtent == rhs.currentExtent )
+          && ( minImageExtent == rhs.minImageExtent )
+          && ( maxImageExtent == rhs.maxImageExtent )
+          && ( maxImageArrayLayers == rhs.maxImageArrayLayers )
+          && ( supportedTransforms == rhs.supportedTransforms )
+          && ( currentTransform == rhs.currentTransform )
+          && ( supportedCompositeAlpha == rhs.supportedCompositeAlpha )
+          && ( supportedUsageFlags == rhs.supportedUsageFlags )
+          && ( supportedSurfaceCounters == rhs.supportedSurfaceCounters );
+    }
+
+    bool operator!=( SurfaceCapabilities2EXT const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    void* pNext;
+    uint32_t minImageCount;
+    uint32_t maxImageCount;
+    Extent2D currentExtent;
+    Extent2D minImageExtent;
+    Extent2D maxImageExtent;
+    uint32_t maxImageArrayLayers;
+    SurfaceTransformFlagsKHR supportedTransforms;
+    SurfaceTransformFlagBitsKHR currentTransform;
+    CompositeAlphaFlagsKHR supportedCompositeAlpha;
+    ImageUsageFlags supportedUsageFlags;
+    SurfaceCounterFlagsEXT supportedSurfaceCounters;
+  };
+  static_assert( sizeof( SurfaceCapabilities2EXT ) == sizeof( VkSurfaceCapabilities2EXT ), "struct and wrapper have different size!" );
+
+  struct SwapchainCounterCreateInfoEXT
+  {
+    SwapchainCounterCreateInfoEXT( SurfaceCounterFlagsEXT surfaceCounters_ = SurfaceCounterFlagsEXT() )
+      : sType( StructureType::eSwapchainCounterCreateInfoEXT )
+      , pNext( nullptr )
+      , surfaceCounters( surfaceCounters_ )
+    {
+    }
+
+    SwapchainCounterCreateInfoEXT( VkSwapchainCounterCreateInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(SwapchainCounterCreateInfoEXT) );
+    }
+
+    SwapchainCounterCreateInfoEXT& operator=( VkSwapchainCounterCreateInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(SwapchainCounterCreateInfoEXT) );
+      return *this;
+    }
+
+    SwapchainCounterCreateInfoEXT& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    SwapchainCounterCreateInfoEXT& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    SwapchainCounterCreateInfoEXT& setSurfaceCounters( SurfaceCounterFlagsEXT surfaceCounters_ )
+    {
+      surfaceCounters = surfaceCounters_;
+      return *this;
+    }
+
+    operator const VkSwapchainCounterCreateInfoEXT&() const
+    {
+      return *reinterpret_cast<const VkSwapchainCounterCreateInfoEXT*>(this);
+    }
+
+    bool operator==( SwapchainCounterCreateInfoEXT const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( surfaceCounters == rhs.surfaceCounters );
+    }
+
+    bool operator!=( SwapchainCounterCreateInfoEXT const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    SurfaceCounterFlagsEXT surfaceCounters;
+  };
+  static_assert( sizeof( SwapchainCounterCreateInfoEXT ) == sizeof( VkSwapchainCounterCreateInfoEXT ), "struct and wrapper have different size!" );
+
+  enum class DisplayPowerStateEXT
+  {
+    eOff = VK_DISPLAY_POWER_STATE_OFF_EXT,
+    eSuspend = VK_DISPLAY_POWER_STATE_SUSPEND_EXT,
+    eOn = VK_DISPLAY_POWER_STATE_ON_EXT
+  };
+
+  struct DisplayPowerInfoEXT
+  {
+    DisplayPowerInfoEXT( DisplayPowerStateEXT powerState_ = DisplayPowerStateEXT::eOff )
+      : sType( StructureType::eDisplayPowerInfoEXT )
+      , pNext( nullptr )
+      , powerState( powerState_ )
+    {
+    }
+
+    DisplayPowerInfoEXT( VkDisplayPowerInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DisplayPowerInfoEXT) );
+    }
+
+    DisplayPowerInfoEXT& operator=( VkDisplayPowerInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DisplayPowerInfoEXT) );
+      return *this;
+    }
+
+    DisplayPowerInfoEXT& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    DisplayPowerInfoEXT& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    DisplayPowerInfoEXT& setPowerState( DisplayPowerStateEXT powerState_ )
+    {
+      powerState = powerState_;
+      return *this;
+    }
+
+    operator const VkDisplayPowerInfoEXT&() const
+    {
+      return *reinterpret_cast<const VkDisplayPowerInfoEXT*>(this);
+    }
+
+    bool operator==( DisplayPowerInfoEXT const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( powerState == rhs.powerState );
+    }
+
+    bool operator!=( DisplayPowerInfoEXT const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    DisplayPowerStateEXT powerState;
+  };
+  static_assert( sizeof( DisplayPowerInfoEXT ) == sizeof( VkDisplayPowerInfoEXT ), "struct and wrapper have different size!" );
+
+  enum class DeviceEventTypeEXT
+  {
+    eDisplayHotplug = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT
+  };
+
+  struct DeviceEventInfoEXT
+  {
+    DeviceEventInfoEXT( DeviceEventTypeEXT deviceEvent_ = DeviceEventTypeEXT::eDisplayHotplug )
+      : sType( StructureType::eDeviceEventInfoEXT )
+      , pNext( nullptr )
+      , deviceEvent( deviceEvent_ )
+    {
+    }
+
+    DeviceEventInfoEXT( VkDeviceEventInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DeviceEventInfoEXT) );
+    }
+
+    DeviceEventInfoEXT& operator=( VkDeviceEventInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DeviceEventInfoEXT) );
+      return *this;
+    }
+
+    DeviceEventInfoEXT& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    DeviceEventInfoEXT& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    DeviceEventInfoEXT& setDeviceEvent( DeviceEventTypeEXT deviceEvent_ )
+    {
+      deviceEvent = deviceEvent_;
+      return *this;
+    }
+
+    operator const VkDeviceEventInfoEXT&() const
+    {
+      return *reinterpret_cast<const VkDeviceEventInfoEXT*>(this);
+    }
+
+    bool operator==( DeviceEventInfoEXT const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( deviceEvent == rhs.deviceEvent );
+    }
+
+    bool operator!=( DeviceEventInfoEXT const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    DeviceEventTypeEXT deviceEvent;
+  };
+  static_assert( sizeof( DeviceEventInfoEXT ) == sizeof( VkDeviceEventInfoEXT ), "struct and wrapper have different size!" );
+
+  enum class DisplayEventTypeEXT
+  {
+    eFirstPixelOut = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT
+  };
+
+  struct DisplayEventInfoEXT
+  {
+    DisplayEventInfoEXT( DisplayEventTypeEXT displayEvent_ = DisplayEventTypeEXT::eFirstPixelOut )
+      : sType( StructureType::eDisplayEventInfoEXT )
+      , pNext( nullptr )
+      , displayEvent( displayEvent_ )
+    {
+    }
+
+    DisplayEventInfoEXT( VkDisplayEventInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DisplayEventInfoEXT) );
+    }
+
+    DisplayEventInfoEXT& operator=( VkDisplayEventInfoEXT const & rhs )
+    {
+      memcpy( this, &rhs, sizeof(DisplayEventInfoEXT) );
+      return *this;
+    }
+
+    DisplayEventInfoEXT& setSType( StructureType sType_ )
+    {
+      sType = sType_;
+      return *this;
+    }
+
+    DisplayEventInfoEXT& setPNext( const void* pNext_ )
+    {
+      pNext = pNext_;
+      return *this;
+    }
+
+    DisplayEventInfoEXT& setDisplayEvent( DisplayEventTypeEXT displayEvent_ )
+    {
+      displayEvent = displayEvent_;
+      return *this;
+    }
+
+    operator const VkDisplayEventInfoEXT&() const
+    {
+      return *reinterpret_cast<const VkDisplayEventInfoEXT*>(this);
+    }
+
+    bool operator==( DisplayEventInfoEXT const& rhs ) const
+    {
+      return ( sType == rhs.sType )
+          && ( pNext == rhs.pNext )
+          && ( displayEvent == rhs.displayEvent );
+    }
+
+    bool operator!=( DisplayEventInfoEXT const& rhs ) const
+    {
+      return !operator==( rhs );
+    }
+
+  private:
+    StructureType sType;
+
+  public:
+    const void* pNext;
+    DisplayEventTypeEXT displayEvent;
+  };
+  static_assert( sizeof( DisplayEventInfoEXT ) == sizeof( VkDisplayEventInfoEXT ), "struct and wrapper have different size!" );
+
   VULKAN_HPP_INLINE Result enumerateInstanceLayerProperties( uint32_t* pPropertyCount, LayerProperties* pProperties )
   {
     return static_cast<Result>( vkEnumerateInstanceLayerProperties( pPropertyCount, reinterpret_cast<VkLayerProperties*>( pProperties ) ) );
@@ -19007,6 +19927,75 @@
     }
 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
 
+#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    void trimCommandPoolKHR( CommandPool commandPool, CommandPoolTrimFlagsKHR flags ) const
+    {
+      vkTrimCommandPoolKHR( m_device, static_cast<VkCommandPool>( commandPool ), static_cast<VkCommandPoolTrimFlagsKHR>( flags ) );
+    }
+#endif /*!VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    void trimCommandPoolKHR( CommandPool commandPool, CommandPoolTrimFlagsKHR flags = CommandPoolTrimFlagsKHR() ) const
+    {
+      vkTrimCommandPoolKHR( m_device, static_cast<VkCommandPool>( commandPool ), static_cast<VkCommandPoolTrimFlagsKHR>( flags ) );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT* pDisplayPowerInfo ) const
+    {
+      return static_cast<Result>( vkDisplayPowerControlEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayPowerInfoEXT*>( pDisplayPowerInfo ) ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<void>::type displayPowerControlEXT( DisplayKHR display, const DisplayPowerInfoEXT & displayPowerInfo ) const
+    {
+      Result result = static_cast<Result>( vkDisplayPowerControlEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayPowerInfoEXT*>( &displayPowerInfo ) ) );
+      return createResultValue( result, "vk::Device::displayPowerControlEXT" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result registerEventEXT( const DeviceEventInfoEXT* pDeviceEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const
+    {
+      return static_cast<Result>( vkRegisterDeviceEventEXT( m_device, reinterpret_cast<const VkDeviceEventInfoEXT*>( pDeviceEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFence*>( pFence ) ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<Fence>::type registerEventEXT( const DeviceEventInfoEXT & deviceEventInfo, const AllocationCallbacks & allocator ) const
+    {
+      Fence fence;
+      Result result = static_cast<Result>( vkRegisterDeviceEventEXT( m_device, reinterpret_cast<const VkDeviceEventInfoEXT*>( &deviceEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( &allocator ), reinterpret_cast<VkFence*>( &fence ) ) );
+      return createResultValue( result, fence, "vk::Device::registerEventEXT" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT* pDisplayEventInfo, const AllocationCallbacks* pAllocator, Fence* pFence ) const
+    {
+      return static_cast<Result>( vkRegisterDisplayEventEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayEventInfoEXT*>( pDisplayEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkFence*>( pFence ) ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<Fence>::type registerDisplayEventEXT( DisplayKHR display, const DisplayEventInfoEXT & displayEventInfo, const AllocationCallbacks & allocator ) const
+    {
+      Fence fence;
+      Result result = static_cast<Result>( vkRegisterDisplayEventEXT( m_device, static_cast<VkDisplayKHR>( display ), reinterpret_cast<const VkDisplayEventInfoEXT*>( &displayEventInfo ), reinterpret_cast<const VkAllocationCallbacks*>( &allocator ), reinterpret_cast<VkFence*>( &fence ) ) );
+      return createResultValue( result, fence, "vk::Device::registerDisplayEventEXT" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue ) const
+    {
+      return static_cast<Result>( vkGetSwapchainCounterEXT( m_device, static_cast<VkSwapchainKHR>( swapchain ), static_cast<VkSurfaceCounterFlagBitsEXT>( counter ), pCounterValue ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValue<uint64_t> getSwapchainCounterEXT( SwapchainKHR swapchain, SurfaceCounterFlagBitsEXT counter ) const
+    {
+      uint64_t counterValue;
+      Result result = static_cast<Result>( vkGetSwapchainCounterEXT( m_device, static_cast<VkSwapchainKHR>( swapchain ), static_cast<VkSurfaceCounterFlagBitsEXT>( counter ), &counterValue ) );
+      return createResultValue( result, counterValue, "vk::Device::getSwapchainCounterEXT", { Result::eSuccess, Result::eErrorDeviceLost, Result::eErrorOutOfDateKHR } );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
 #if !defined(VULKAN_HPP_TYPESAFE_CONVERSION)
     explicit
 #endif
@@ -19564,6 +20553,176 @@
     }
 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
 
+    void getFeatures2KHR( PhysicalDeviceFeatures2KHR* pFeatures ) const
+    {
+      vkGetPhysicalDeviceFeatures2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures2KHR*>( pFeatures ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    PhysicalDeviceFeatures2KHR getFeatures2KHR() const
+    {
+      PhysicalDeviceFeatures2KHR features;
+      vkGetPhysicalDeviceFeatures2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceFeatures2KHR*>( &features ) );
+      return features;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    void getProperties2KHR( PhysicalDeviceProperties2KHR* pProperties ) const
+    {
+      vkGetPhysicalDeviceProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties2KHR*>( pProperties ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    PhysicalDeviceProperties2KHR getProperties2KHR() const
+    {
+      PhysicalDeviceProperties2KHR properties;
+      vkGetPhysicalDeviceProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceProperties2KHR*>( &properties ) );
+      return properties;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    void getFormatProperties2KHR( Format format, FormatProperties2KHR* pFormatProperties ) const
+    {
+      vkGetPhysicalDeviceFormatProperties2KHR( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties2KHR*>( pFormatProperties ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    FormatProperties2KHR getFormatProperties2KHR( Format format ) const
+    {
+      FormatProperties2KHR formatProperties;
+      vkGetPhysicalDeviceFormatProperties2KHR( m_physicalDevice, static_cast<VkFormat>( format ), reinterpret_cast<VkFormatProperties2KHR*>( &formatProperties ) );
+      return formatProperties;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, ImageFormatProperties2KHR* pImageFormatProperties ) const
+    {
+      return static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>( pImageFormatInfo ), reinterpret_cast<VkImageFormatProperties2KHR*>( pImageFormatProperties ) ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<ImageFormatProperties2KHR>::type getImageFormatProperties2KHR( const PhysicalDeviceImageFormatInfo2KHR & imageFormatInfo ) const
+    {
+      ImageFormatProperties2KHR imageFormatProperties;
+      Result result = static_cast<Result>( vkGetPhysicalDeviceImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceImageFormatInfo2KHR*>( &imageFormatInfo ), reinterpret_cast<VkImageFormatProperties2KHR*>( &imageFormatProperties ) ) );
+      return createResultValue( result, imageFormatProperties, "vk::PhysicalDevice::getImageFormatProperties2KHR" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    void getQueueFamilyProperties2KHR( uint32_t* pQueueFamilyPropertyCount, QueueFamilyProperties2KHR* pQueueFamilyProperties ) const
+    {
+      vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, pQueueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties2KHR*>( pQueueFamilyProperties ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    template <typename Allocator = std::allocator<QueueFamilyProperties2KHR>>
+    std::vector<QueueFamilyProperties2KHR,Allocator> getQueueFamilyProperties2KHR() const
+    {
+      std::vector<QueueFamilyProperties2KHR,Allocator> queueFamilyProperties;
+      uint32_t queueFamilyPropertyCount;
+      vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, &queueFamilyPropertyCount, nullptr );
+      queueFamilyProperties.resize( queueFamilyPropertyCount );
+      vkGetPhysicalDeviceQueueFamilyProperties2KHR( m_physicalDevice, &queueFamilyPropertyCount, reinterpret_cast<VkQueueFamilyProperties2KHR*>( queueFamilyProperties.data() ) );
+      return queueFamilyProperties;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    void getMemoryProperties2KHR( PhysicalDeviceMemoryProperties2KHR* pMemoryProperties ) const
+    {
+      vkGetPhysicalDeviceMemoryProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties2KHR*>( pMemoryProperties ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    PhysicalDeviceMemoryProperties2KHR getMemoryProperties2KHR() const
+    {
+      PhysicalDeviceMemoryProperties2KHR memoryProperties;
+      vkGetPhysicalDeviceMemoryProperties2KHR( m_physicalDevice, reinterpret_cast<VkPhysicalDeviceMemoryProperties2KHR*>( &memoryProperties ) );
+      return memoryProperties;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    void getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, SparseImageFormatProperties2KHR* pProperties ) const
+    {
+      vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( pFormatInfo ), pPropertyCount, reinterpret_cast<VkSparseImageFormatProperties2KHR*>( pProperties ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    template <typename Allocator = std::allocator<SparseImageFormatProperties2KHR>>
+    std::vector<SparseImageFormatProperties2KHR,Allocator> getSparseImageFormatProperties2KHR( const PhysicalDeviceSparseImageFormatInfo2KHR & formatInfo ) const
+    {
+      std::vector<SparseImageFormatProperties2KHR,Allocator> properties;
+      uint32_t propertyCount;
+      vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( &formatInfo ), &propertyCount, nullptr );
+      properties.resize( propertyCount );
+      vkGetPhysicalDeviceSparseImageFormatProperties2KHR( m_physicalDevice, reinterpret_cast<const VkPhysicalDeviceSparseImageFormatInfo2KHR*>( &formatInfo ), &propertyCount, reinterpret_cast<VkSparseImageFormatProperties2KHR*>( properties.data() ) );
+      return properties;
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+#ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    Result releaseDisplayEXT( DisplayKHR display ) const
+    {
+      return static_cast<Result>( vkReleaseDisplayEXT( m_physicalDevice, static_cast<VkDisplayKHR>( display ) ) );
+    }
+#endif /*!VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<void>::type releaseDisplayEXT( DisplayKHR display ) const
+    {
+      Result result = static_cast<Result>( vkReleaseDisplayEXT( m_physicalDevice, static_cast<VkDisplayKHR>( display ) ) );
+      return createResultValue( result, "vk::PhysicalDevice::releaseDisplayEXT" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    Result acquireXlibDisplayEXT( Display* dpy, DisplayKHR display ) const
+    {
+      return static_cast<Result>( vkAcquireXlibDisplayEXT( m_physicalDevice, dpy, static_cast<VkDisplayKHR>( display ) ) );
+    }
+#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    ResultValueType<Display>::type acquireXlibDisplayEXT( DisplayKHR display ) const
+    {
+      Display dpy;
+      Result result = static_cast<Result>( vkAcquireXlibDisplayEXT( m_physicalDevice, &dpy, static_cast<VkDisplayKHR>( display ) ) );
+      return createResultValue( result, dpy, "vk::PhysicalDevice::acquireXlibDisplayEXT" );
+    }
+#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    Result getRandROutputDisplayEXT( Display* dpy, RROutput rrOutput, DisplayKHR* pDisplay ) const
+    {
+      return static_cast<Result>( vkGetRandROutputDisplayEXT( m_physicalDevice, dpy, rrOutput, reinterpret_cast<VkDisplayKHR*>( pDisplay ) ) );
+    }
+#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    ResultValueType<void>::type getRandROutputDisplayEXT( Display & dpy, RROutput rrOutput, DisplayKHR & display ) const
+    {
+      Result result = static_cast<Result>( vkGetRandROutputDisplayEXT( m_physicalDevice, &dpy, rrOutput, reinterpret_cast<VkDisplayKHR*>( &display ) ) );
+      return createResultValue( result, "vk::PhysicalDevice::getRandROutputDisplayEXT" );
+    }
+#endif /*VK_USE_PLATFORM_XLIB_XRANDR_EXT*/
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
+    Result getSurfaceCapabilities2EXT( SurfaceKHR surface, SurfaceCapabilities2EXT* pSurfaceCapabilities ) const
+    {
+      return static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2EXT( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilities2EXT*>( pSurfaceCapabilities ) ) );
+    }
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+    ResultValueType<SurfaceCapabilities2EXT>::type getSurfaceCapabilities2EXT( SurfaceKHR surface ) const
+    {
+      SurfaceCapabilities2EXT surfaceCapabilities;
+      Result result = static_cast<Result>( vkGetPhysicalDeviceSurfaceCapabilities2EXT( m_physicalDevice, static_cast<VkSurfaceKHR>( surface ), reinterpret_cast<VkSurfaceCapabilities2EXT*>( &surfaceCapabilities ) ) );
+      return createResultValue( result, surfaceCapabilities, "vk::PhysicalDevice::getSurfaceCapabilities2EXT" );
+    }
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
 #if !defined(VULKAN_HPP_TYPESAFE_CONVERSION)
     explicit
 #endif
@@ -19734,6 +20893,24 @@
     }
 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
 
+#ifdef VK_USE_PLATFORM_VI_NN
+    Result createViSurfaceNN( const ViSurfaceCreateInfoNN* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const
+    {
+      return static_cast<Result>( vkCreateViSurfaceNN( m_instance, reinterpret_cast<const VkViSurfaceCreateInfoNN*>( pCreateInfo ), reinterpret_cast<const VkAllocationCallbacks*>( pAllocator ), reinterpret_cast<VkSurfaceKHR*>( pSurface ) ) );
+    }
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
+#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
+#ifdef VK_USE_PLATFORM_VI_NN
+    ResultValueType<SurfaceKHR>::type createViSurfaceNN( const ViSurfaceCreateInfoNN & createInfo, Optional<const AllocationCallbacks> allocator = nullptr ) const
+    {
+      SurfaceKHR surface;
+      Result result = static_cast<Result>( vkCreateViSurfaceNN( m_instance, reinterpret_cast<const VkViSurfaceCreateInfoNN*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator)), reinterpret_cast<VkSurfaceKHR*>( &surface ) ) );
+      return createResultValue( result, surface, "vk::Instance::createViSurfaceNN" );
+    }
+#endif /*VK_USE_PLATFORM_VI_NN*/
+#endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
+
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
     Result createWaylandSurfaceKHR( const WaylandSurfaceCreateInfoKHR* pCreateInfo, const AllocationCallbacks* pAllocator, SurfaceKHR* pSurface ) const
     {
@@ -20372,6 +21549,20 @@
   }
 #endif /*VK_USE_PLATFORM_MIR_KHR*/
 
+#ifdef VK_USE_PLATFORM_VI_NN
+  VULKAN_HPP_INLINE std::string to_string(ViSurfaceCreateFlagBitsNN)
+  {
+    return "(void)";
+  }
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
+#ifdef VK_USE_PLATFORM_VI_NN
+  VULKAN_HPP_INLINE std::string to_string(ViSurfaceCreateFlagsNN)
+  {
+    return "{}";
+  }
+#endif /*VK_USE_PLATFORM_VI_NN*/
+
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
   VULKAN_HPP_INLINE std::string to_string(WaylandSurfaceCreateFlagBitsKHR)
   {
@@ -20428,6 +21619,16 @@
   }
 #endif /*VK_USE_PLATFORM_XCB_KHR*/
 
+  VULKAN_HPP_INLINE std::string to_string(CommandPoolTrimFlagBitsKHR)
+  {
+    return "(void)";
+  }
+
+  VULKAN_HPP_INLINE std::string to_string(CommandPoolTrimFlagsKHR)
+  {
+    return "{}";
+  }
+
   VULKAN_HPP_INLINE std::string to_string(ImageLayout value)
   {
     switch (value)
@@ -21127,13 +22328,28 @@
     case StructureType::eImportMemoryWin32HandleInfoNV: return "ImportMemoryWin32HandleInfoNV";
     case StructureType::eExportMemoryWin32HandleInfoNV: return "ExportMemoryWin32HandleInfoNV";
     case StructureType::eWin32KeyedMutexAcquireReleaseInfoNV: return "Win32KeyedMutexAcquireReleaseInfoNV";
+    case StructureType::ePhysicalDeviceFeatures2KHR: return "PhysicalDeviceFeatures2KHR";
+    case StructureType::ePhysicalDeviceProperties2KHR: return "PhysicalDeviceProperties2KHR";
+    case StructureType::eFormatProperties2KHR: return "FormatProperties2KHR";
+    case StructureType::eImageFormatProperties2KHR: return "ImageFormatProperties2KHR";
+    case StructureType::ePhysicalDeviceImageFormatInfo2KHR: return "PhysicalDeviceImageFormatInfo2KHR";
+    case StructureType::eQueueFamilyProperties2KHR: return "QueueFamilyProperties2KHR";
+    case StructureType::ePhysicalDeviceMemoryProperties2KHR: return "PhysicalDeviceMemoryProperties2KHR";
+    case StructureType::eSparseImageFormatProperties2KHR: return "SparseImageFormatProperties2KHR";
+    case StructureType::ePhysicalDeviceSparseImageFormatInfo2KHR: return "PhysicalDeviceSparseImageFormatInfo2KHR";
     case StructureType::eValidationFlagsEXT: return "ValidationFlagsEXT";
+    case StructureType::eViSurfaceCreateInfoNN: return "ViSurfaceCreateInfoNN";
     case StructureType::eObjectTableCreateInfoNVX: return "ObjectTableCreateInfoNVX";
     case StructureType::eIndirectCommandsLayoutCreateInfoNVX: return "IndirectCommandsLayoutCreateInfoNVX";
     case StructureType::eCmdProcessCommandsInfoNVX: return "CmdProcessCommandsInfoNVX";
     case StructureType::eCmdReserveSpaceForCommandsInfoNVX: return "CmdReserveSpaceForCommandsInfoNVX";
     case StructureType::eDeviceGeneratedCommandsLimitsNVX: return "DeviceGeneratedCommandsLimitsNVX";
     case StructureType::eDeviceGeneratedCommandsFeaturesNVX: return "DeviceGeneratedCommandsFeaturesNVX";
+    case StructureType::eSurfaceCapabilities2EXT: return "SurfaceCapabilities2EXT";
+    case StructureType::eDisplayPowerInfoEXT: return "DisplayPowerInfoEXT";
+    case StructureType::eDeviceEventInfoEXT: return "DeviceEventInfoEXT";
+    case StructureType::eDisplayEventInfoEXT: return "DisplayEventInfoEXT";
+    case StructureType::eSwapchainCounterCreateInfoEXT: return "SwapchainCounterCreateInfoEXT";
     default: return "invalid";
     }
   }
@@ -21408,6 +22624,7 @@
     case ImageCreateFlagBits::eSparseAliased: return "SparseAliased";
     case ImageCreateFlagBits::eMutableFormat: return "MutableFormat";
     case ImageCreateFlagBits::eCubeCompatible: return "CubeCompatible";
+    case ImageCreateFlagBits::e2DArrayCompatibleKHR: return "2DArrayCompatibleKHR";
     default: return "invalid";
     }
   }
@@ -21421,6 +22638,7 @@
     if (value & ImageCreateFlagBits::eSparseAliased) result += "SparseAliased | ";
     if (value & ImageCreateFlagBits::eMutableFormat) result += "MutableFormat | ";
     if (value & ImageCreateFlagBits::eCubeCompatible) result += "CubeCompatible | ";
+    if (value & ImageCreateFlagBits::e2DArrayCompatibleKHR) result += "2DArrayCompatibleKHR | ";
     return "{" + result.substr(0, result.size() - 3) + "}";
   }
 
@@ -21503,6 +22721,8 @@
     case FormatFeatureFlagBits::eBlitDst: return "BlitDst";
     case FormatFeatureFlagBits::eSampledImageFilterLinear: return "SampledImageFilterLinear";
     case FormatFeatureFlagBits::eSampledImageFilterCubicIMG: return "SampledImageFilterCubicIMG";
+    case FormatFeatureFlagBits::eTransferSrcKHR: return "TransferSrcKHR";
+    case FormatFeatureFlagBits::eTransferDstKHR: return "TransferDstKHR";
     default: return "invalid";
     }
   }
@@ -21525,6 +22745,8 @@
     if (value & FormatFeatureFlagBits::eBlitDst) result += "BlitDst | ";
     if (value & FormatFeatureFlagBits::eSampledImageFilterLinear) result += "SampledImageFilterLinear | ";
     if (value & FormatFeatureFlagBits::eSampledImageFilterCubicIMG) result += "SampledImageFilterCubicIMG | ";
+    if (value & FormatFeatureFlagBits::eTransferSrcKHR) result += "TransferSrcKHR | ";
+    if (value & FormatFeatureFlagBits::eTransferDstKHR) result += "TransferDstKHR | ";
     return "{" + result.substr(0, result.size() - 3) + "}";
   }
 
@@ -21909,6 +23131,18 @@
     switch (value)
     {
     case ColorSpaceKHR::eSrgbNonlinear: return "SrgbNonlinear";
+    case ColorSpaceKHR::eDisplayP3LinearEXT: return "DisplayP3LinearEXT";
+    case ColorSpaceKHR::eDisplayP3NonlinearEXT: return "DisplayP3NonlinearEXT";
+    case ColorSpaceKHR::eScrgbLinearEXT: return "ScrgbLinearEXT";
+    case ColorSpaceKHR::eScrgbNonlinearEXT: return "ScrgbNonlinearEXT";
+    case ColorSpaceKHR::eDciP3LinearEXT: return "DciP3LinearEXT";
+    case ColorSpaceKHR::eDciP3NonlinearEXT: return "DciP3NonlinearEXT";
+    case ColorSpaceKHR::eBt709LinearEXT: return "Bt709LinearEXT";
+    case ColorSpaceKHR::eBt709NonlinearEXT: return "Bt709NonlinearEXT";
+    case ColorSpaceKHR::eBt2020LinearEXT: return "Bt2020LinearEXT";
+    case ColorSpaceKHR::eBt2020NonlinearEXT: return "Bt2020NonlinearEXT";
+    case ColorSpaceKHR::eAdobergbLinearEXT: return "AdobergbLinearEXT";
+    case ColorSpaceKHR::eAdobergbNonlinearEXT: return "AdobergbNonlinearEXT";
     default: return "invalid";
     }
   }
@@ -22202,6 +23436,52 @@
     }
   }
 
+  VULKAN_HPP_INLINE std::string to_string(SurfaceCounterFlagBitsEXT value)
+  {
+    switch (value)
+    {
+    case SurfaceCounterFlagBitsEXT::eVblankExt: return "VblankExt";
+    default: return "invalid";
+    }
+  }
+
+  VULKAN_HPP_INLINE std::string to_string(SurfaceCounterFlagsEXT value)
+  {
+    if (!value) return "{}";
+    std::string result;
+    if (value & SurfaceCounterFlagBitsEXT::eVblankExt) result += "VblankExt | ";
+    return "{" + result.substr(0, result.size() - 3) + "}";
+  }
+
+  VULKAN_HPP_INLINE std::string to_string(DisplayPowerStateEXT value)
+  {
+    switch (value)
+    {
+    case DisplayPowerStateEXT::eOff: return "Off";
+    case DisplayPowerStateEXT::eSuspend: return "Suspend";
+    case DisplayPowerStateEXT::eOn: return "On";
+    default: return "invalid";
+    }
+  }
+
+  VULKAN_HPP_INLINE std::string to_string(DeviceEventTypeEXT value)
+  {
+    switch (value)
+    {
+    case DeviceEventTypeEXT::eDisplayHotplug: return "DisplayHotplug";
+    default: return "invalid";
+    }
+  }
+
+  VULKAN_HPP_INLINE std::string to_string(DisplayEventTypeEXT value)
+  {
+    switch (value)
+    {
+    case DisplayEventTypeEXT::eFirstPixelOut: return "FirstPixelOut";
+    default: return "invalid";
+    }
+  }
+
 } // namespace vk
 
 #endif
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index b32cf6c..eb4ef7a 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -11,7 +11,7 @@
     endif()
 
     if (BUILD_WSI_XLIB_SUPPORT)
-       add_definitions(-DVK_USE_PLATFORM_XLIB_KHR)
+       add_definitions(-DVK_USE_PLATFORM_XLIB_KHR -DVK_USE_PLATFORM_XLIB_XRANDR_EXT)
     endif()
 
     if (BUILD_WSI_WAYLAND_SUPPORT)
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 651320d..bb7ce82 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -116,6 +116,8 @@
 
     CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
     uint32_t physical_devices_count = 0;
+    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
+    uint32_t physical_device_groups_count = 0;
     CHECK_DISABLED disabled = {};
 
     unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
@@ -180,6 +182,8 @@
 static unordered_map<void *, layer_data *> layer_data_map;
 static unordered_map<void *, instance_layer_data *> instance_layer_data_map;
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static const VkLayerProperties global_layer = {
     "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
 };
@@ -4101,7 +4105,6 @@
     instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), instance_layer_data_map);
     instance_data->instance = *pInstance;
     layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
-
     instance_data->report_data = debug_report_create_instance(
         &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
     checkInstanceRegisterExtensions(pCreateInfo, instance_data);
@@ -12864,6 +12867,9 @@
 static PFN_vkVoidFunction
 intercept_khr_surface_command(const char *name, VkInstance instance);
 
+static PFN_vkVoidFunction
+intercept_extension_instance_commands(const char *name, VkInstance instance);
+
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
     PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
     if (proc)
@@ -12901,12 +12907,27 @@
     if (proc)
         return proc;
 
+    proc = intercept_extension_instance_commands(funcName, instance);
+    if (proc)
+        return proc;
+
     auto &table = instance_data->dispatch_table;
     if (!table.GetInstanceProcAddr)
         return nullptr;
     return table.GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
+
+    auto &table = instance_data->dispatch_table;
+    if (!table.GetPhysicalDeviceProcAddr)
+        return nullptr;
+    return table.GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 static PFN_vkVoidFunction
 intercept_core_instance_command(const char *name) {
     static const struct {
@@ -12914,6 +12935,7 @@
         PFN_vkVoidFunction proc;
     } core_instance_commands[] = {
         { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
+        { "vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr) },
         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
         { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
         { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
@@ -13163,6 +13185,11 @@
     return nullptr;
 }
 
+static PFN_vkVoidFunction
+intercept_extension_instance_commands(const char *name, VkInstance instance) {
+    return NULL;
+}
+
 } // namespace core_validation
 
 // vk_layer_logging.h expects these to be defined
@@ -13220,3 +13247,28 @@
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
     return core_validation::GetInstanceProcAddr(instance, funcName);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
+
diff --git a/layers/image.cpp b/layers/image.cpp
index 45786f8..8e79e99 100644
--- a/layers/image.cpp
+++ b/layers/image.cpp
@@ -72,6 +72,8 @@
           physicalDeviceProperties(){};
 };
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static unordered_map<void *, layer_data *> layer_data_map;
 static std::mutex global_lock;
 
@@ -136,7 +138,6 @@
     my_data->instance = *pInstance;
     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
-
     my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
                                                         pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
 
@@ -1319,6 +1320,17 @@
     return pTable->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+
+    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
+    if (pTable->GetPhysicalDeviceProcAddr == NULL)
+        return NULL;
+    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 static PFN_vkVoidFunction
 intercept_core_instance_command(const char *name) {
     static const struct {
@@ -1334,6 +1346,7 @@
         { "vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties) },
         { "vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties) },
         { "vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties) },
+        { "vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr) },
     };
 
     for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
@@ -1432,3 +1445,27 @@
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
     return image::GetInstanceProcAddr(instance, funcName);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return image::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        image::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/linux/VkLayer_core_validation.json b/layers/linux/VkLayer_core_validation.json
index 31c48c0..7fb94d2 100644
--- a/layers/linux/VkLayer_core_validation.json
+++ b/layers/linux/VkLayer_core_validation.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_core_validation",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_core_validation.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_image.json b/layers/linux/VkLayer_image.json
index 97df791..39dd4e6 100644
--- a/layers/linux/VkLayer_image.json
+++ b/layers/linux/VkLayer_image.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_image",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_image.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_object_tracker.json b/layers/linux/VkLayer_object_tracker.json
index c48afdf..95bf280 100644
--- a/layers/linux/VkLayer_object_tracker.json
+++ b/layers/linux/VkLayer_object_tracker.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_object_tracker",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_object_tracker.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_parameter_validation.json b/layers/linux/VkLayer_parameter_validation.json
index a9abaa3..d679e66 100644
--- a/layers/linux/VkLayer_parameter_validation.json
+++ b/layers/linux/VkLayer_parameter_validation.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_parameter_validation",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_parameter_validation.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_swapchain.json b/layers/linux/VkLayer_swapchain.json
index 6a2691e..f9feb06 100644
--- a/layers/linux/VkLayer_swapchain.json
+++ b/layers/linux/VkLayer_swapchain.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_swapchain",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_swapchain.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_threading.json b/layers/linux/VkLayer_threading.json
index 2d87cc1..2b0a3a3 100644
--- a/layers/linux/VkLayer_threading.json
+++ b/layers/linux/VkLayer_threading.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_GOOGLE_threading",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_threading.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "Google Validation Layer",
         "instance_extensions": [
diff --git a/layers/linux/VkLayer_unique_objects.json b/layers/linux/VkLayer_unique_objects.json
index b9a87d5..a5f7a6f 100644
--- a/layers/linux/VkLayer_unique_objects.json
+++ b/layers/linux/VkLayer_unique_objects.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_GOOGLE_unique_objects",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_unique_objects.so",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "Google Validation Layer"
     }
diff --git a/layers/object_tracker.cpp b/layers/object_tracker.cpp
index 00d19f3..fb3354b 100644
--- a/layers/object_tracker.cpp
+++ b/layers/object_tracker.cpp
@@ -46,6 +46,8 @@
 
 namespace object_tracker {
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static void InitObjectTracker(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
 
     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_object_tracker");
@@ -573,6 +575,8 @@
 
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *pName);
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
+
 VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount,
                                                                     VkExtensionProperties *pProperties);
 
@@ -3150,6 +3154,8 @@
     device_data->wsi_display_swapchain_enabled = false;
     device_data->wsi_display_extension_enabled = false;
     device_data->objtrack_extensions_enabled = false;
+    device_data->nvx_device_generated_commands_enabled = false;
+    device_data->ext_display_control_enabled = false;
 
     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
@@ -3164,12 +3170,17 @@
         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], "OBJTRACK_EXTENSIONS") == 0) {
             device_data->objtrack_extensions_enabled = true;
         }
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME) == 0) {
+            device_data->nvx_device_generated_commands_enabled = true;
+        }
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME) == 0) {
+            device_data->ext_display_control_enabled = true;
+        }
     }
 }
 
 static void CheckInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
     VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(ot_instance_table_map, instance);
- 
 
     instanceExtMap[pDisp] = {};
 
@@ -3979,6 +3990,405 @@
     }
 }
 
+// VK_KHR_get_physical_device_properties2 Extension
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)->GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                           VkPhysicalDeviceProperties2KHR *pProperties) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)->GetPhysicalDeviceProperties2KHR(physicalDevice, pProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format,
+                                                                 VkFormatProperties2KHR *pFormatProperties) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)
+            ->GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, pFormatProperties);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
+    VkImageFormatProperties2KHR *pImageFormatProperties) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                 ->GetPhysicalDeviceImageFormatProperties2KHR(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                      uint32_t *pQueueFamilyPropertyCount,
+                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)
+            ->GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                 VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)
+            ->GetPhysicalDeviceMemoryProperties2KHR(physicalDevice, pMemoryProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
+    VkSparseImageFormatProperties2KHR *pProperties) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (!skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)
+            ->GetPhysicalDeviceSparseImageFormatProperties2KHR(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+    }
+}
+
+// VK_NVX_device_generated_commands Extension
+VKAPI_ATTR void VKAPI_CALL CmdProcessCommandsNVX(VkCommandBuffer commandBuffer,
+                                                 const VkCmdProcessCommandsInfoNVX *pProcessCommandsInfo) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(commandBuffer, commandBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, false,
+                                VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (!skip_call && dev_data->dispatch_table.CmdProcessCommandsNVX) {
+        dev_data->dispatch_table.CmdProcessCommandsNVX(commandBuffer, pProcessCommandsInfo);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdReserveSpaceForCommandsNVX(VkCommandBuffer commandBuffer,
+                                                         const VkCmdReserveSpaceForCommandsInfoNVX *pReserveSpaceInfo) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(commandBuffer, commandBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, false,
+                                VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (!skip_call && dev_data->dispatch_table.CmdReserveSpaceForCommandsNVX) {
+        dev_data->dispatch_table.CmdReserveSpaceForCommandsNVX(commandBuffer, pReserveSpaceInfo);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateIndirectCommandsLayoutNVX(VkDevice device,
+                                                               const VkIndirectCommandsLayoutCreateInfoNVX *pCreateInfo,
+                                                               const VkAllocationCallbacks *pAllocator,
+                                                               VkIndirectCommandsLayoutNVX *pIndirectCommandsLayout) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.CreateIndirectCommandsLayoutNVX) {
+        result = dev_data->dispatch_table.CreateIndirectCommandsLayoutNVX(device, pCreateInfo, pAllocator, pIndirectCommandsLayout);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyIndirectCommandsLayoutNVX(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout,
+                                                            const VkAllocationCallbacks *pAllocator) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (!skip_call) {
+        layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+        if (dev_data->dispatch_table.DestroyIndirectCommandsLayoutNVX) {
+            dev_data->dispatch_table.DestroyIndirectCommandsLayoutNVX(device, indirectCommandsLayout, pAllocator);
+        }
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateObjectTableNVX(VkDevice device, const VkObjectTableCreateInfoNVX *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkObjectTableNVX *pObjectTable) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.CreateObjectTableNVX) {
+        result = dev_data->dispatch_table.CreateObjectTableNVX(device, pCreateInfo, pAllocator, pObjectTable);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyObjectTableNVX(VkDevice device, VkObjectTableNVX objectTable,
+                                                 const VkAllocationCallbacks *pAllocator) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (!skip_call) {
+        layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+        if (dev_data->dispatch_table.DestroyObjectTableNVX) {
+            dev_data->dispatch_table.DestroyObjectTableNVX(device, objectTable, pAllocator);
+        }
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL RegisterObjectsNVX(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount,
+                                                  const VkObjectTableEntryNVX *const *ppObjectTableEntries,
+                                                  const uint32_t *pObjectIndices) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.RegisterObjectsNVX) {
+        result =
+            dev_data->dispatch_table.RegisterObjectsNVX(device, objectTable, objectCount, ppObjectTableEntries, pObjectIndices);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL UnregisterObjectsNVX(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount,
+                                                    const VkObjectEntryTypeNVX *pObjectEntryTypes, const uint32_t *pObjectIndices) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.UnregisterObjectsNVX) {
+        result = dev_data->dispatch_table.UnregisterObjectsNVX(device, objectTable, objectCount, pObjectEntryTypes, pObjectIndices);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceGeneratedCommandsPropertiesNVX(VkPhysicalDevice physicalDevice,
+                                                                           VkDeviceGeneratedCommandsFeaturesNVX *pFeatures,
+                                                                           VkDeviceGeneratedCommandsLimitsNVX *pLimits) {
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        get_dispatch_table(ot_instance_table_map, physicalDevice)
+            ->GetPhysicalDeviceGeneratedCommandsPropertiesNVX(physicalDevice, pFeatures, pLimits);
+    }
+}
+
+// VK_EXT_direct_mode_display Extension
+VKAPI_ATTR VkResult VKAPI_CALL ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    result = get_dispatch_table(ot_instance_table_map, physicalDevice)->ReleaseDisplayEXT(physicalDevice, display);
+
+    return result;
+}
+
+// VK_EXT_acquire_xlib_display Extension
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VKAPI_ATTR VkResult VKAPI_CALL AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    result = get_dispatch_table(ot_instance_table_map, physicalDevice)->AcquireXlibDisplayEXT(physicalDevice, dpy, display);
+
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
+                                                        VkDisplayKHR *pDisplay) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                 ->GetRandROutputDisplayEXT(physicalDevice, dpy, rrOutput, pDisplay);
+    if (result == VK_SUCCESS && pDisplay != NULL) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        CreateObject(physicalDevice, pDisplay, VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT, nullptr);
+    }
+
+    return result;
+}
+#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+// VK_EXT_display_surface_counter Extension
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip = false;
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= ValidateObject(physicalDevice, physicalDevice, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, false,
+                               VALIDATION_ERROR_UNDEFINED);
+    }
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    result = get_dispatch_table(ot_instance_table_map, physicalDevice)
+                 ->GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
+
+    return result;
+}
+
+// VK_EXT_display_control Extension
+VKAPI_ATTR VkResult VKAPI_CALL DisplayPowerControlEXT(VkDevice device, VkDisplayKHR display,
+                                                      const VkDisplayPowerInfoEXT *pDisplayPowerInfo) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.DisplayPowerControlEXT) {
+        result = dev_data->dispatch_table.DisplayPowerControlEXT(device, display, pDisplayPowerInfo);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL RegisterDeviceEventEXT(VkDevice device, const VkDeviceEventInfoEXT *pDeviceEventInfo,
+                                                      const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.RegisterDeviceEventEXT) {
+        result = dev_data->dispatch_table.RegisterDeviceEventEXT(device, pDeviceEventInfo, pAllocator, pFence);
+        if (result == VK_SUCCESS && pFence != NULL) {
+            std::lock_guard<std::mutex> lock(global_lock);
+            CreateObject(device, *pFence, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, pAllocator);
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL RegisterDisplayEventEXT(VkDevice device, VkDisplayKHR display,
+                                                       const VkDisplayEventInfoEXT *pDisplayEventInfo,
+                                                       const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.RegisterDisplayEventEXT) {
+        result = dev_data->dispatch_table.RegisterDisplayEventEXT(device, display, pDisplayEventInfo, pAllocator, pFence);
+        if (result == VK_SUCCESS && pFence != NULL) {
+            std::lock_guard<std::mutex> lock(global_lock);
+            CreateObject(device, *pFence, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, pAllocator);
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainCounterEXT(VkDevice device, VkSwapchainKHR swapchain,
+                                                      VkSurfaceCounterFlagBitsEXT counter, uint64_t *pCounterValue) {
+    bool skip_call = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip_call |= ValidateObject(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip_call) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (dev_data->dispatch_table.GetSwapchainCounterEXT) {
+        result = dev_data->dispatch_table.GetSwapchainCounterEXT(device, swapchain, counter, pCounterValue);
+    }
+    return result;
+}
 
 static inline PFN_vkVoidFunction InterceptCoreDeviceCommand(const char *name) {
     if (!name || name[0] != 'v' || name[1] != 'k')
@@ -4248,6 +4658,7 @@
 
     return NULL;
 }
+
 static inline PFN_vkVoidFunction InterceptCoreInstanceCommand(const char *name) {
     if (!name || name[0] != 'v' || name[1] != 'k')
         return NULL;
@@ -4259,6 +4670,8 @@
         return (PFN_vkVoidFunction)DestroyInstance;
     if (!strcmp(name, "EnumeratePhysicalDevices"))
         return (PFN_vkVoidFunction)EnumeratePhysicalDevices;
+    if (!strcmp(name, "_layerGetPhysicalDeviceProcAddr"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceProcAddr;
     if (!strcmp(name, "GetPhysicalDeviceFeatures"))
         return (PFN_vkVoidFunction)GetPhysicalDeviceFeatures;
     if (!strcmp(name, "GetPhysicalDeviceFormatProperties"))
@@ -4289,6 +4702,89 @@
     return NULL;
 }
 
+static inline PFN_vkVoidFunction InterceptDeviceExtensionCommand(const char *name, VkDevice device) {
+    if (device) {
+        layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+        if (!name || name[0] != 'v' || name[1] != 'k')
+            return NULL;
+
+        name += 2;
+
+        if (device_data->nvx_device_generated_commands_enabled) {
+            if (!strcmp(name, "CmdProcessCommandsNVX"))
+                return (PFN_vkVoidFunction)CmdProcessCommandsNVX;
+            if (!strcmp(name, "CmdReserveSpaceForCommandsNVX"))
+                return (PFN_vkVoidFunction)CmdReserveSpaceForCommandsNVX;
+            if (!strcmp(name, "CreateIndirectCommandsLayoutNVX"))
+                return (PFN_vkVoidFunction)CreateIndirectCommandsLayoutNVX;
+            if (!strcmp(name, "DestroyIndirectCommandsLayoutNVX"))
+                return (PFN_vkVoidFunction)DestroyIndirectCommandsLayoutNVX;
+            if (!strcmp(name, "CreateObjectTableNVX"))
+                return (PFN_vkVoidFunction)CreateObjectTableNVX;
+            if (!strcmp(name, "DestroyObjectTableNVX"))
+                return (PFN_vkVoidFunction)DestroyObjectTableNVX;
+            if (!strcmp(name, "RegisterObjectsNVX"))
+                return (PFN_vkVoidFunction)RegisterObjectsNVX;
+            if (!strcmp(name, "UnregisterObjectsNVX"))
+                return (PFN_vkVoidFunction)UnregisterObjectsNVX;
+        }
+        if (device_data->ext_display_control_enabled) {
+            if (!strcmp(name, "DisplayPowerControlEXT"))
+                return (PFN_vkVoidFunction)DisplayPowerControlEXT;
+            if (!strcmp(name, "RegisterDeviceEventEXT"))
+                return (PFN_vkVoidFunction)RegisterDeviceEventEXT;
+            if (!strcmp(name, "RegisterDisplayEventEXT"))
+                return (PFN_vkVoidFunction)RegisterDisplayEventEXT;
+            if (!strcmp(name, "GetSwapchainCounterEXT"))
+                return (PFN_vkVoidFunction)GetSwapchainCounterEXT;
+        }
+    }
+
+    return NULL;
+}
+
+static inline PFN_vkVoidFunction InterceptInstanceExtensionCommand(const char *name) {
+    if (!name || name[0] != 'v' || name[1] != 'k')
+        return NULL;
+
+    name += 2;
+
+    // VK_KHR_get_physical_device_properties2 Extension
+    if (!strcmp(name, "GetPhysicalDeviceFeatures2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceFeatures2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceFormatProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceFormatProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceImageFormatProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceImageFormatProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceQueueFamilyProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceQueueFamilyProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceMemoryProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceMemoryProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties2KHR"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceSparseImageFormatProperties2KHR;
+    // VK_NVX_device_generated_commands Extension
+    if (!strcmp(name, "GetPhysicalDeviceGeneratedCommandsPropertiesNVX"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceGeneratedCommandsPropertiesNVX;
+    // VK_EXT_direct_mode_display Extension
+    if (!strcmp(name, "ReleaseDisplayEXT"))
+        return (PFN_vkVoidFunction)ReleaseDisplayEXT;
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // VK_EXT_acquire_xlib_display Extension
+    if (!strcmp(name, "AcquireXlibDisplayEXT"))
+        return (PFN_vkVoidFunction)AcquireXlibDisplayEXT;
+    if (!strcmp(name, "GetRandROutputDisplayEXT"))
+        return (PFN_vkVoidFunction)GetRandROutputDisplayEXT;
+#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // VK_EXT_display_surface_counter Extension
+    if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilities2EXT"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceSurfaceCapabilities2EXT;
+
+    return NULL;
+}
+
 static inline PFN_vkVoidFunction InterceptWsiEnabledCommand(const char *name, VkDevice device) {
     if (device) {
         layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
@@ -4345,6 +4841,10 @@
     if (addr) {
         return addr;
     }
+    addr = InterceptDeviceExtensionCommand(funcName, device);
+    if (addr) {
+        return addr;
+    }
     if (get_dispatch_table(ot_device_table_map, device)->GetDeviceProcAddr == NULL) {
         return NULL;
     }
@@ -4373,12 +4873,25 @@
     if (addr) {
         return addr;
     }
+    addr = InterceptInstanceExtensionCommand(funcName);
+    if (addr) {
+        return addr;
+    }
     if (get_dispatch_table(ot_instance_table_map, instance)->GetInstanceProcAddr == NULL) {
         return NULL;
     }
     return get_dispatch_table(ot_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    if (get_dispatch_table(ot_instance_table_map, instance)->GetPhysicalDeviceProcAddr == NULL) {
+        return NULL;
+    }
+    return get_dispatch_table(ot_instance_table_map, instance)->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 } // namespace object_tracker
 
 // vk_layer_logging.h expects these to be defined
@@ -4433,3 +4946,27 @@
     assert(physicalDevice == VK_NULL_HANDLE);
     return object_tracker::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return object_tracker::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        object_tracker::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/object_tracker.h b/layers/object_tracker.h
index 078e7f0..d34bd03 100644
--- a/layers/object_tracker.h
+++ b/layers/object_tracker.h
@@ -98,6 +98,8 @@
     bool wsi_display_swapchain_enabled;
     bool wsi_display_extension_enabled;
     bool objtrack_extensions_enabled;
+    bool nvx_device_generated_commands_enabled;
+    bool ext_display_control_enabled;
 
     // The following are for keeping track of the temporary callbacks that can
     // be used in vkCreateInstance and vkDestroyInstance:
diff --git a/layers/parameter_validation.cpp b/layers/parameter_validation.cpp
index 970fc7b..332fd8b 100644
--- a/layers/parameter_validation.cpp
+++ b/layers/parameter_validation.cpp
@@ -77,14 +77,28 @@
     VkPhysicalDeviceFeatures physical_device_features = {};
     VkPhysicalDevice physical_device = VK_NULL_HANDLE;
 
-    bool swapchain_enabled = false;
-    bool display_swapchain_enabled = false;
-    bool amd_negative_viewport_height_enabled = false;
-    bool nvx_device_generated_commands_enabled = false;
+    union loader_device_extension_enables {
+        struct {
+            bool khr_swapchain_enabled : 1;
+            bool khr_display_swapchain_enabled : 1;
+            bool khr_maintenance1 : 1;
+            bool ext_debug_marker : 1;
+            bool amd_negative_viewport_height : 1;
+            bool nv_external_memory : 1;
+            bool nv_external_memory_win32 : 1;
+            bool nvx_device_generated_commands : 1;
+        };
+        uint64_t padding[4];
+    } enables;
+
+    layer_data() {
+        memset(enables.padding, 0, sizeof(uint64_t) * 4);
+    }
 
     VkLayerDispatchTable dispatch_table = {};
 };
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
 static std::unordered_map<void *, layer_data *> layer_data_map;
 static std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;
 
@@ -1559,61 +1573,71 @@
 
         if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.surface_enabled = true;
-        }
 #ifdef VK_USE_PLATFORM_XLIB_KHR
-        if (strcmp(name, VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.xlib_enabled = true;
-        }
 #endif
 #ifdef VK_USE_PLATFORM_XCB_KHR
-        if (strcmp(name, VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.xcb_enabled = true;
-        }
 #endif
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
-        if (strcmp(name, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.wayland_enabled = true;
-        }
 #endif
 #ifdef VK_USE_PLATFORM_MIR_KHR
-        if (strcmp(name, VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.mir_enabled = true;
-        }
 #endif
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
-        if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.android_enabled = true;
-        }
 #endif
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-        if (strcmp(name, VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) {
             instance_data->extensions.win32_enabled = true;
-        }
 #endif
-        if (strcmp(name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0) {
+        } else if (strcmp(name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0) {
             instance_data->extensions.display_enabled = true;
+        } else if (strcmp(name, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) {
+            instance_data->extensions.khr_get_phys_dev_properties2_enabled = true;
+        } else if (strcmp(name, VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME) == 0) {
+            instance_data->extensions.nv_external_memory_capabilities_enabled = true;
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+        } else if (strcmp(name, VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME) == 0) {
+            instance_data->extensions.ext_acquire_xlib_display_enabled = true;
+#endif
+        } else if (strcmp(name, VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME) == 0) {
+            instance_data->extensions.ext_direct_mode_display_enabled = true;
+        } else if (strcmp(name, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME) == 0) {
+            instance_data->extensions.ext_display_surface_counter_enabled = true;
+        } else if (strcmp(name, VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME) == 0) {
+            instance_data->extensions.nv_external_memory_capabilities_enabled = true;
         }
     }
 }
 
 static void CheckDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
     layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    device_data->swapchain_enabled = false;
-    device_data->display_swapchain_enabled = false;
-    device_data->amd_negative_viewport_height_enabled = false;
-
     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
-            device_data->swapchain_enabled = true;
-        }
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
-            device_data->display_swapchain_enabled = true;
-        }
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0) {
-            device_data->amd_negative_viewport_height_enabled = true;
-        }
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME) == 0) {
-            device_data->nvx_device_generated_commands_enabled = true;
+            device_data->enables.khr_swapchain_enabled = true;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
+            device_data->enables.khr_display_swapchain_enabled = true;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MAINTENANCE1_EXTENSION_NAME) == 0) {
+            device_data->enables.khr_maintenance1 = true;
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0) {
+            device_data->enables.nv_external_memory_win32 = true;
+#endif
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME) == 0) {
+            device_data->enables.ext_debug_marker = true;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0) {
+            device_data->enables.amd_negative_viewport_height = true;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME) == 0) {
+            device_data->enables.nv_external_memory = true;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME) == 0) {
+            device_data->enables.nvx_device_generated_commands = true;
         }
     }
 }
@@ -3995,7 +4019,7 @@
             }
 
             bool invalid_height = (viewport.height <= 0 || viewport.height > limits.maxViewportDimensions[1]);
-            if (my_data->amd_negative_viewport_height_enabled && (viewport.height < 0)) {
+            if (my_data->enables.amd_negative_viewport_height && (viewport.height < 0)) {
                 // VALIDATION_ERROR_01790
                 invalid_height = false;
             }
@@ -4817,9 +4841,9 @@
         ->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
 }
 
-static bool require_device_extension(layer_data *my_data, bool layer_data::*flag, char const *function_name, char const *extension_name)
+static bool require_device_extension(layer_data *my_data, bool flag, char const *function_name, char const *extension_name)
 {
-    if (!(my_data->*flag)) {
+    if (!flag) {
         return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                        __LINE__, EXTENSION_NOT_ENABLED, LayerName,
                        "%s() called even though the %s extension was not enabled for this VkDevice.",
@@ -4838,7 +4862,7 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::swapchain_enabled, "vkCreateSwapchainKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_swapchain_enabled, "vkCreateSwapchainKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
     skip |= parameter_validation_vkCreateSwapchainKHR(my_data->report_data, pCreateInfo, pAllocator, pSwapchain);
 
@@ -4858,7 +4882,7 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::swapchain_enabled, "vkGetSwapchainImagesKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_swapchain_enabled, "vkGetSwapchainImagesKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
     skip |=
         parameter_validation_vkGetSwapchainImagesKHR(my_data->report_data, swapchain, pSwapchainImageCount, pSwapchainImages);
@@ -4879,7 +4903,7 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::swapchain_enabled, "vkAcquireNextImageKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_swapchain_enabled, "vkAcquireNextImageKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
     skip |=
         parameter_validation_vkAcquireNextImageKHR(my_data->report_data, swapchain, timeout, semaphore, fence, pImageIndex);
@@ -4899,7 +4923,7 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::swapchain_enabled, "vkQueuePresentKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_swapchain_enabled, "vkQueuePresentKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
     skip |= parameter_validation_vkQueuePresentKHR(my_data->report_data, pPresentInfo);
 
@@ -4917,7 +4941,7 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::swapchain_enabled, "vkDestroySwapchainKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_swapchain_enabled, "vkDestroySwapchainKHR", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
     /* No generated validation function for this call */
 
@@ -5280,8 +5304,8 @@
     assert(my_data != NULL);
     bool skip = false;
 
-    skip |= require_instance_extension(instance, &instance_extension_enables::android_enabled,
-                                            "vkCreateAndroidSurfaceKHR", VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
+    skip |= require_instance_extension(instance, &instance_extension_enables::android_enabled, "vkCreateAndroidSurfaceKHR",
+                                       VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
 
     skip |= parameter_validation_vkCreateAndroidSurfaceKHR(my_data->report_data, pCreateInfo, pAllocator, pSurface);
 
@@ -5303,10 +5327,11 @@
     auto my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_device_extension(my_data, &layer_data::display_swapchain_enabled, "vkCreateSharedSwapchainsKHR", VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.khr_display_swapchain_enabled, "vkCreateSharedSwapchainsKHR",
+                                     VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME);
 
     skip |= parameter_validation_vkCreateSharedSwapchainsKHR(my_data->report_data, swapchainCount, pCreateInfos, pAllocator,
-                                                                  pSwapchains);
+                                                             pSwapchains);
 
     if (!skip) {
         result = my_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
@@ -5409,8 +5434,8 @@
     auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::display_enabled,
-                                       "vkCreateDisplayModeKHR", VK_KHR_DISPLAY_EXTENSION_NAME);
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::display_enabled, "vkCreateDisplayModeKHR",
+                                       VK_KHR_DISPLAY_EXTENSION_NAME);
 
     // No parameter validation function for this call?
 
@@ -5451,8 +5476,8 @@
     auto my_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
     assert(my_data != NULL);
 
-    skip |= require_instance_extension(instance, &instance_extension_enables::display_enabled,
-                                       "vkCreateDisplayPlaneSurfaceKHR", VK_KHR_DISPLAY_EXTENSION_NAME);
+    skip |= require_instance_extension(instance, &instance_extension_enables::display_enabled, "vkCreateDisplayPlaneSurfaceKHR",
+                                       VK_KHR_DISPLAY_EXTENSION_NAME);
 
     // No parameter validation function for this call?
 
@@ -5465,13 +5490,204 @@
     return result;
 }
 
-// VK_EXT_debug_marker Extension
+// Definitions for the VK_KHR_get_physical_device_properties2 extension
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |=
+        require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                   "vkGetPhysicalDeviceFeatures2KHR", VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceFeatures2KHR(my_data->report_data, pFeatures);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                           VkPhysicalDeviceProperties2KHR *pProperties) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |=
+        require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                   "vkGetPhysicalDeviceProperties2KHR", VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceProperties2KHR(my_data->report_data, pProperties);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceProperties2KHR(physicalDevice, pProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format,
+                                                                 VkFormatProperties2KHR *pFormatProperties) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                            "vkGetPhysicalDeviceFormatProperties2KHR",
+                                            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceFormatProperties2KHR(my_data->report_data, format, pFormatProperties);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, pFormatProperties);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
+    VkImageFormatProperties2KHR *pImageFormatProperties) {
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                            "vkGetPhysicalDeviceImageFormatProperties2KHR",
+                                            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceImageFormatProperties2KHR(my_data->report_data, pImageFormatInfo,
+                                                                                   pImageFormatProperties);
+
+    if (!skip_call) {
+        result = my_data->dispatch_table.GetPhysicalDeviceImageFormatProperties2KHR(physicalDevice, pImageFormatInfo,
+                                                                                    pImageFormatProperties);
+        validate_result(my_data->report_data, "vkGetPhysicalDeviceImageFormatProperties2KHR", result);
+    }
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                      uint32_t *pQueueFamilyPropertyCount,
+                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                            "vkGetPhysicalDeviceQueueFamilyProperties2KHR",
+                                            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceQueueFamilyProperties2KHR(my_data->report_data, pQueueFamilyPropertyCount,
+                                                                                   pQueueFamilyProperties);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
+                                                                           pQueueFamilyProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                 VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                            "vkGetPhysicalDeviceMemoryProperties2KHR",
+                                            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceMemoryProperties2KHR(my_data->report_data, pMemoryProperties);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceMemoryProperties2KHR(physicalDevice, pMemoryProperties);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
+    VkSparseImageFormatProperties2KHR *pProperties) {
+    bool skip_call = false;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_instance_extension(physicalDevice, &instance_extension_enables::khr_get_phys_dev_properties2_enabled,
+                                            "vkGetPhysicalDeviceSparseImageFormatProperties2KHR",
+                                            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkGetPhysicalDeviceSparseImageFormatProperties2KHR(my_data->report_data, pFormatInfo,
+                                                                                         pPropertyCount, pProperties);
+
+    if (!skip_call) {
+        my_data->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties2KHR(physicalDevice, pFormatInfo, pPropertyCount,
+                                                                                 pProperties);
+    }
+}
+
+// Definitions for the VK_KHR_maintenance1 extension
+
+VKAPI_ATTR void VKAPI_CALL TrimCommandPoolKHR(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags) {
+    bool skip_call = false;
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    assert(my_data != NULL);
+
+    skip_call |= require_device_extension(my_data, my_data->enables.khr_maintenance1, "vkTrimCommandPoolKHR",
+                                          VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+
+    skip_call |= parameter_validation_vkTrimCommandPoolKHR(my_data->report_data, commandPool, flags);
+
+    if (!skip_call) {
+        my_data->dispatch_table.TrimCommandPoolKHR(device, commandPool, flags);
+    }
+}
+
+// Definitions for the VK_EXT_acquire_xlib_display extension
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VKAPI_ATTR VkResult VKAPI_CALL AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
+
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+    bool skip = false;
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::ext_acquire_xlib_display_enabled,
+                                       "vkAcquireXlibDisplayEXT", VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME);
+    skip |= parameter_validation_vkAcquireXlibDisplayEXT(my_data->report_data, dpy, display);
+    if (!skip) {
+        result = my_data->dispatch_table.AcquireXlibDisplayEXT(physicalDevice, dpy, display);
+        validate_result(my_data->report_data, "vkAcquireXlibDisplayEXT", result);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
+                                                        VkDisplayKHR *pDisplay) {
+
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+    bool skip = false;
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::ext_acquire_xlib_display_enabled,
+                                       "vkGetRandROutputDisplayEXT", VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME);
+    skip |= parameter_validation_vkGetRandROutputDisplayEXT(my_data->report_data, dpy, rrOutput, pDisplay);
+    if (!skip) {
+        result = my_data->dispatch_table.GetRandROutputDisplayEXT(physicalDevice, dpy, rrOutput, pDisplay);
+        validate_result(my_data->report_data, "vkGetRandROutputDisplayEXT", result);
+    }
+    return result;
+}
+#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+// Definitions for the VK_EXT_debug_marker Extension
+
 VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectTagEXT(VkDevice device, VkDebugMarkerObjectTagInfoEXT *pTagInfo) {
     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_device_extension(my_data, my_data->enables.ext_debug_marker, "vkDebugMarkerSetObjectTagEXT",
+                                     VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
+
     skip |= parameter_validation_vkDebugMarkerSetObjectTagEXT(my_data->report_data, pTagInfo);
 
     if (!skip) {
@@ -5492,6 +5708,9 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_device_extension(my_data, my_data->enables.ext_debug_marker, "vkDebugMarkerSetObjectNameEXT",
+                                     VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
+
     skip |= parameter_validation_vkDebugMarkerSetObjectNameEXT(my_data->report_data, pNameInfo);
 
     if (!skip) {
@@ -5511,6 +5730,9 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_device_extension(my_data, my_data->enables.ext_debug_marker, "vkCmdDebugMarkerBeginEXT",
+                                     VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
+
     skip |= parameter_validation_vkCmdDebugMarkerBeginEXT(my_data->report_data, pMarkerInfo);
 
     if (!skip && my_data->dispatch_table.CmdDebugMarkerBeginEXT) {
@@ -5523,6 +5745,9 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_device_extension(my_data, my_data->enables.ext_debug_marker, "vkCmdDebugMarkerInsertEXT",
+                                     VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
+
     skip |= parameter_validation_vkCmdDebugMarkerInsertEXT(my_data->report_data, pMarkerInfo);
 
     if (!skip && my_data->dispatch_table.CmdDebugMarkerInsertEXT) {
@@ -5530,7 +5755,48 @@
     }
 }
 
-// VK_NV_external_memory_capabilities Extension
+// Definitions for the VK_EXT_direct_mode_display extension
+
+VKAPI_ATTR VkResult VKAPI_CALL ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
+
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+    bool skip = false;
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::ext_direct_mode_display_enabled,
+                                       "vkReleaseDisplayEXT", VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME);
+#if 0 // Validation not automatically generated
+    skip |= parameter_validation_vkReleaseDisplayEXT(my_data->report_data, display);
+#endif
+    if (!skip) {
+        result = my_data->dispatch_table.ReleaseDisplayEXT(physicalDevice, display);
+        validate_result(my_data->report_data, "vkGetRandROutputDisplayEXT", result);
+    }
+    return result;
+}
+
+// Definitions for the VK_EXT_display_surface_counter extension
+
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
+
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+    auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    assert(my_data != NULL);
+    bool skip = false;
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::ext_display_surface_counter_enabled,
+                                       "vkGetPhysicalDeviceSurfaceCapabilities2EXT", VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
+    skip |=
+        parameter_validation_vkGetPhysicalDeviceSurfaceCapabilities2EXT(my_data->report_data, surface, pSurfaceCapabilities);
+    if (!skip) {
+        result = my_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
+        validate_result(my_data->report_data, "vkGetPhysicalDeviceSurfaceCapabilities2EXT", result);
+    }
+    return result;
+}
+
+// Definitions for the VK_NV_external_memory_capabilities Extension
+
 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceExternalImageFormatPropertiesNV(
     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage,
     VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType,
@@ -5541,6 +5807,10 @@
     auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_instance_extension(physicalDevice, &instance_extension_enables::nv_external_memory_capabilities_enabled,
+                                       "vkGetPhysicalDeviceExternalImageFormatPropertiesNV",
+                                       VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
+
     skip |= parameter_validation_vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
         my_data->report_data, format, type, tiling, usage, flags, externalHandleType, pExternalImageFormatProperties);
 
@@ -5554,8 +5824,9 @@
     return result;
 }
 
-#ifdef VK_USE_PLATFORM_WIN32_KHR
 // VK_NV_external_memory_win32 Extension
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
 VKAPI_ATTR VkResult VKAPI_CALL GetMemoryWin32HandleNV(VkDevice device, VkDeviceMemory memory,
                                                       VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE *pHandle) {
 
@@ -5564,6 +5835,9 @@
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
 
+    skip |= require_device_extension(my_data, my_data->enables.nv_external_memory_win32, "vkGetMemoryWin32HandleNV",
+                                     VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
+
     skip |= parameter_validation_vkGetMemoryWin32HandleNV(my_data->report_data, memory, handleType, pHandle);
 
     if (!skip) {
@@ -5574,37 +5848,31 @@
 }
 #endif // VK_USE_PLATFORM_WIN32_KHR
 
-// VK_NVX_device_generated_commands extension
+// VK_NVX_device_generated_commands Extension
 
 VKAPI_ATTR void VKAPI_CALL CmdProcessCommandsNVX(VkCommandBuffer commandBuffer,
                                                  const VkCmdProcessCommandsInfoNVX *pProcessCommandsInfo) {
     bool skip = false;
-    layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
-    assert(device_data != nullptr);
-    debug_report_data *report_data = device_data->report_data;
-
-    skip |= require_device_extension(device_data, &layer_data::nvx_device_generated_commands_enabled, "vkCmdProcessCommandsNVX",
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    assert(my_data != NULL);
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkCmdProcessCommandsNVX",
                                      VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
-    skip |= parameter_validation_vkCmdProcessCommandsNVX(report_data, pProcessCommandsInfo);
-
+    skip |= parameter_validation_vkCmdProcessCommandsNVX(my_data->report_data, pProcessCommandsInfo);
     if (!skip) {
-        device_data->dispatch_table.CmdProcessCommandsNVX(commandBuffer, pProcessCommandsInfo);
+        my_data->dispatch_table.CmdProcessCommandsNVX(commandBuffer, pProcessCommandsInfo);
     }
 }
 
 VKAPI_ATTR void VKAPI_CALL CmdReserveSpaceForCommandsNVX(VkCommandBuffer commandBuffer,
                                                          const VkCmdReserveSpaceForCommandsInfoNVX *pReserveSpaceInfo) {
     bool skip = false;
-    layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
-    assert(device_data != nullptr);
-    debug_report_data *report_data = device_data->report_data;
-
-    skip |= require_device_extension(device_data, &layer_data::nvx_device_generated_commands_enabled,
-                                     "vkCmdReserveSpaceForCommandsNVX", VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
-    skip |= parameter_validation_vkCmdReserveSpaceForCommandsNVX(report_data, pReserveSpaceInfo);
-
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    assert(my_data != NULL);
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkCmdReserveSpaceForCommandsNVX",
+                                     VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
+    skip |= parameter_validation_vkCmdReserveSpaceForCommandsNVX(my_data->report_data, pReserveSpaceInfo);
     if (!skip) {
-        device_data->dispatch_table.CmdReserveSpaceForCommandsNVX(commandBuffer, pReserveSpaceInfo);
+        my_data->dispatch_table.CmdReserveSpaceForCommandsNVX(commandBuffer, pReserveSpaceInfo);
     }
 }
 
@@ -5616,13 +5884,12 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled,
-                                     "vkCreateIndirectCommandsLayoutNVX", VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkCreateIndirectCommandsLayoutNVX",
+                                     VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
     skip |= parameter_validation_vkCreateIndirectCommandsLayoutNVX(my_data->report_data, pCreateInfo, pAllocator,
                                                                    pIndirectCommandsLayout);
     if (!skip) {
         result = my_data->dispatch_table.CreateIndirectCommandsLayoutNVX(device, pCreateInfo, pAllocator, pIndirectCommandsLayout);
-
         validate_result(my_data->report_data, "vkCreateIndirectCommandsLayoutNVX", result);
     }
     return result;
@@ -5633,9 +5900,11 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled,
-                                     "vkDestroyIndirectCommandsLayoutNVX", VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkDestroyIndirectCommandsLayoutNVX",
+                                     VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
+#if 0 // Validation not automatically generated
     skip |= parameter_validation_vkDestroyIndirectCommandsLayoutNVX(my_data->report_data, indirectCommandsLayout, pAllocator);
+#endif
     if (!skip) {
         my_data->dispatch_table.DestroyIndirectCommandsLayoutNVX(device, indirectCommandsLayout, pAllocator);
     }
@@ -5647,11 +5916,12 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled, "vkCreateObjectTableNVX",
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkCreateObjectTableNVX",
                                      VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
     skip |= parameter_validation_vkCreateObjectTableNVX(my_data->report_data, pCreateInfo, pAllocator, pObjectTable);
     if (!skip) {
         result = my_data->dispatch_table.CreateObjectTableNVX(device, pCreateInfo, pAllocator, pObjectTable);
+        validate_result(my_data->report_data, "vkCreateObjectTableNVX", result);
     }
     return result;
 }
@@ -5661,9 +5931,11 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled, "vkDestroyObjectTableNVX",
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkDestroyObjectTableNVX",
                                      VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
+#if 0 // Validation not automatically generated
     skip |= parameter_validation_vkDestroyObjectTableNVX(my_data->report_data, objectTable, pAllocator);
+#endif
     if (!skip) {
         my_data->dispatch_table.DestroyObjectTableNVX(device, objectTable, pAllocator);
     }
@@ -5676,12 +5948,13 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled, "vkRegisterObjectsNVX",
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkRegisterObjectsNVX",
                                      VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
     skip |= parameter_validation_vkRegisterObjectsNVX(my_data->report_data, objectTable, objectCount, ppObjectTableEntries,
                                                       pObjectIndices);
     if (!skip) {
         result = my_data->dispatch_table.RegisterObjectsNVX(device, objectTable, objectCount, ppObjectTableEntries, pObjectIndices);
+        validate_result(my_data->report_data, "vkRegisterObjectsNVX", result);
     }
     return result;
 }
@@ -5692,12 +5965,13 @@
     bool skip = false;
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     assert(my_data != NULL);
-    skip |= require_device_extension(my_data, &layer_data::nvx_device_generated_commands_enabled, "vkUnregisterObjectsNVX",
+    skip |= require_device_extension(my_data, my_data->enables.nvx_device_generated_commands, "vkUnregisterObjectsNVX",
                                      VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
     skip |= parameter_validation_vkUnregisterObjectsNVX(my_data->report_data, objectTable, objectCount, pObjectEntryTypes,
                                                         pObjectIndices);
     if (!skip) {
         result = my_data->dispatch_table.UnregisterObjectsNVX(device, objectTable, objectCount, pObjectEntryTypes, pObjectIndices);
+        validate_result(my_data->report_data, "vkUnregisterObjectsNVX", result);
     }
     return result;
 }
@@ -5708,9 +5982,7 @@
     bool skip = false;
     auto my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
     assert(my_data != NULL);
-
     skip |= parameter_validation_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(my_data->report_data, pFeatures, pLimits);
-
     if (!skip) {
         my_data->dispatch_table.GetPhysicalDeviceGeneratedCommandsPropertiesNVX(physicalDevice, pFeatures, pLimits);
     }
@@ -5724,6 +5996,10 @@
 
 static PFN_vkVoidFunction InterceptWsiEnabledCommand(const char *name, VkInstance instance);
 
+static PFN_vkVoidFunction intercept_extension_instance_command(const char *name, VkInstance instance);
+
+static PFN_vkVoidFunction intercept_extension_device_command(const char *name, VkDevice device);
+
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
     assert(device);
 
@@ -5741,6 +6017,10 @@
     if (proc)
         return proc;
 
+    proc = intercept_extension_device_command(funcName, device);
+    if (proc)
+        return proc;
+
     if (!data->dispatch_table.GetDeviceProcAddr)
         return nullptr;
     return data->dispatch_table.GetDeviceProcAddr(device, funcName);
@@ -5765,6 +6045,9 @@
     if (!proc)
         proc = InterceptWsiEnabledCommand(funcName, instance);
 
+    if (!proc)
+        proc = intercept_extension_instance_command(funcName, instance);
+
     if (proc)
         return proc;
 
@@ -5773,6 +6056,15 @@
     return data->dispatch_table.GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+    auto data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
+
+    if (!data->dispatch_table.GetPhysicalDeviceProcAddr)
+        return nullptr;
+    return data->dispatch_table.GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 static PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
     static const struct {
         const char *name;
@@ -5783,6 +6075,7 @@
         {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
         {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
         {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
+        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
         {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties)},
         {"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFeatures)},
         {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFormatProperties)},
@@ -5976,6 +6269,10 @@
             if (!strcmp(wsi_device_commands[i].name, name))
                 return wsi_device_commands[i].proc;
         }
+
+        if (!strcmp("vkCreateSharedSwapchainsKHR", name)) {
+            return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
+        }
     }
 
     return nullptr;
@@ -6034,6 +6331,70 @@
     return nullptr;
 }
 
+static PFN_vkVoidFunction intercept_extension_instance_command(const char *name, VkInstance instance) {
+    static const struct {
+        const char *name;
+        PFN_vkVoidFunction proc;
+    } extension_instance_commands[] = {
+        {"vkGetPhysicalDeviceFeatures2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFeatures2KHR)},
+        {"vkGetPhysicalDeviceProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties2KHR)},
+        {"vkGetPhysicalDeviceFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFormatProperties2KHR)},
+        {"vkGetPhysicalDeviceImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceImageFormatProperties2KHR)},
+        {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2KHR)},
+        {"vkGetPhysicalDeviceMemoryProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceMemoryProperties2KHR)},
+        {"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSparseImageFormatProperties2KHR)},
+        // NV_external_memory_capabilities
+        {"vkGetPhysicalDeviceExternalImageFormatPropertiesNV",
+         reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceExternalImageFormatPropertiesNV)},
+        // NVX_device_generated_commands
+        {"vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceGeneratedCommandsPropertiesNVX)},
+    };
+
+    for (size_t i = 0; i < ARRAY_SIZE(extension_instance_commands); i++) {
+        if (!strcmp(extension_instance_commands[i].name, name))
+            return extension_instance_commands[i].proc;
+    }
+
+    return nullptr;
+}
+
+static PFN_vkVoidFunction intercept_extension_device_command(const char *name, VkDevice device) {
+    struct ExtProc {
+        const char *name;
+        PFN_vkVoidFunction proc;
+    } extension_device_commands[] = {
+        // KHR_maintenance1
+        {"vkTrimCommandPoolKHR", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPoolKHR)},
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+        // NV_external_memory_win32
+        {"vkGetMemoryWin32HandleNV", reinterpret_cast<PFN_vkVoidFunction>(GetMemoryWin32HandleNV)},
+#endif // VK_USE_PLATFORM_WIN32_KHR
+        // EXT_debug_marker
+        {"vkDebugMarkerSetObjectTagEXT", reinterpret_cast<PFN_vkVoidFunction>(DebugMarkerSetObjectTagEXT)},
+        {"vkDebugMarkerSetObjectNameEXT", reinterpret_cast<PFN_vkVoidFunction>(DebugMarkerSetObjectNameEXT)},
+        {"vkCmdDebugMarkerBeginEXT", reinterpret_cast<PFN_vkVoidFunction>(CmdDebugMarkerBeginEXT)},
+        {"vkCmdDebugMarkerInsertEXT", reinterpret_cast<PFN_vkVoidFunction>(CmdDebugMarkerInsertEXT)},
+        // NVX_device_generated_commands
+        {"vkCmdProcessCommandsNVX", reinterpret_cast<PFN_vkVoidFunction>(CmdProcessCommandsNVX)},
+        {"vkCmdReserveSpaceForCommandsNVX", reinterpret_cast<PFN_vkVoidFunction>(CmdReserveSpaceForCommandsNVX)},
+        {"vkCreateIndirectCommandsLayoutNVX", reinterpret_cast<PFN_vkVoidFunction>(CreateIndirectCommandsLayoutNVX)},
+        {"vkDestroyIndirectCommandsLayoutNVX", reinterpret_cast<PFN_vkVoidFunction>(DestroyIndirectCommandsLayoutNVX)},
+        {"vkCreateObjectTableNVX", reinterpret_cast<PFN_vkVoidFunction>(CreateObjectTableNVX)},
+        {"vkDestroyObjectTableNVX", reinterpret_cast<PFN_vkVoidFunction>(DestroyObjectTableNVX)},
+        {"vkRegisterObjectsNVX", reinterpret_cast<PFN_vkVoidFunction>(RegisterObjectsNVX)},
+        {"vkUnregisterObjectsNVX", reinterpret_cast<PFN_vkVoidFunction>(UnregisterObjectsNVX)},
+    };
+
+    if (device) {
+        for (size_t i = 0; i < ARRAY_SIZE(extension_device_commands); i++) {
+            if (!strcmp(extension_device_commands[i].name, name))
+                return extension_device_commands[i].proc;
+        }
+    }
+
+    return nullptr;
+}
+
 } // namespace parameter_validation
 
 // vk_layer_logging.h expects these to be defined
@@ -6090,3 +6451,27 @@
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
     return parameter_validation::GetInstanceProcAddr(instance, funcName);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return parameter_validation::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        parameter_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/parameter_validation_utils.h b/layers/parameter_validation_utils.h
index 4e4fd81..7c6e605 100644
--- a/layers/parameter_validation_utils.h
+++ b/layers/parameter_validation_utils.h
@@ -81,6 +81,11 @@
     bool android_enabled;
     bool win32_enabled;
     bool display_enabled;
+    bool khr_get_phys_dev_properties2_enabled;
+    bool ext_acquire_xlib_display_enabled;
+    bool ext_direct_mode_display_enabled;
+    bool ext_display_surface_counter_enabled;
+    bool nv_external_memory_capabilities_enabled;
 };
 
 // String returned by string_VkStructureType for an unrecognized type.
@@ -272,47 +277,6 @@
 }
 
 /**
- * Validate an array of Vulkan structures.
- *
- * Verify that required count and array parameters are not NULL.  If count
- * is not NULL and its value is not optional, verify that it is not 0.
- * If the array contains 1 or more structures, verify that each structure's
- * sType field is set to the correct VkStructureType value.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param sTypeName Name of expected VkStructureType value.
- * @param count Pointer to the number of elements in the array.
- * @param array Array to validate.
- * @param sType VkStructureType for structure validation.
- * @param countPtrRequired The 'count' parameter may not be NULL when true.
- * @param countValueRequired The '*count' value may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                                const ParameterName &arrayName, const char *sTypeName, const uint32_t *count, const T *array,
-                                VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
-    bool skip_call = false;
-
-    if (count == NULL) {
-        if (countPtrRequired) {
-            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                                 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
-                                 countName.get_name().c_str());
-        }
-    } else {
-        skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
-                                                countValueRequired, arrayRequired);
-    }
-
-    return skip_call;
-}
-
-/**
  * Validate an array of Vulkan structures
  *
  * Verify that required count and array parameters are not 0 or NULL.  If
@@ -354,6 +318,47 @@
 }
 
 /**
+ * Validate an array of Vulkan structures.
+ *
+ * Verify that required count and array parameters are not NULL.  If count
+ * is not NULL and its value is not optional, verify that it is not 0.
+ * If the array contains 1 or more structures, verify that each structure's
+ * sType field is set to the correct VkStructureType value.
+ *
+ * @param report_data debug_report_data object for routing validation messages.
+ * @param apiName Name of API call being validated.
+ * @param countName Name of count parameter.
+ * @param arrayName Name of array parameter.
+ * @param sTypeName Name of expected VkStructureType value.
+ * @param count Pointer to the number of elements in the array.
+ * @param array Array to validate.
+ * @param sType VkStructureType for structure validation.
+ * @param countPtrRequired The 'count' parameter may not be NULL when true.
+ * @param countValueRequired The '*count' value may not be 0 when true.
+ * @param arrayRequired The 'array' parameter may not be NULL when true.
+ * @return Boolean value indicating that the call should be skipped.
+ */
+template <typename T>
+bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
+                                const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
+                                VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired) {
+    bool skip_call = false;
+
+    if (count == NULL) {
+        if (countPtrRequired) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                                 REQUIRED_PARAMETER, LayerName, "%s: required parameter %s specified as NULL", apiName,
+                                 countName.get_name().c_str());
+        }
+    } else {
+        skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
+                                                countValueRequired, arrayRequired);
+    }
+
+    return skip_call;
+}
+
+/**
 * Validate a Vulkan handle.
 *
 * Verify that the specified handle is not VK_NULL_HANDLE.
diff --git a/layers/swapchain.cpp b/layers/swapchain.cpp
index c7f1ca0..80eefcd 100644
--- a/layers/swapchain.cpp
+++ b/layers/swapchain.cpp
@@ -39,6 +39,8 @@
 // The following is for logging error messages:
 static std::unordered_map<void *, layer_data *> layer_data_map;
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
 
 static const VkLayerProperties swapchain_layer = {
@@ -161,7 +163,6 @@
     my_data->instance = *pInstance;
     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
-
     my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
                                                         pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
 
@@ -1366,6 +1367,18 @@
     return pTable->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    layer_data *my_data;
+    my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
+
+    if (pTable->GetPhysicalDeviceProcAddr == NULL)
+        return NULL;
+    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 static PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
     static const struct {
         const char *name;
@@ -1376,6 +1389,7 @@
         {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
         {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
         {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
+        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
         {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
         {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
         {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
@@ -1537,3 +1551,27 @@
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
     return swapchain::GetInstanceProcAddr(instance, funcName);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return swapchain::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        swapchain::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/threading.cpp b/layers/threading.cpp
index f73774c..2f931e7 100644
--- a/layers/threading.cpp
+++ b/layers/threading.cpp
@@ -39,6 +39,8 @@
 
 namespace threading {
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static void initThreading(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
 
     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "google_threading");
@@ -220,6 +222,9 @@
     return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
 }
 
+// Need to prototype this call because it's internal and does not show up in vk.xml
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
+
 static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name) {
     if (!name || name[0] != 'v' || name[1] != 'k')
         return NULL;
@@ -241,6 +246,8 @@
         return (PFN_vkVoidFunction)CreateDevice;
     if (!strcmp(name, "GetInstanceProcAddr"))
         return (PFN_vkVoidFunction)GetInstanceProcAddr;
+    if (!strcmp(name, "GetPhysicalDeviceProcAddr"))
+        return (PFN_vkVoidFunction)GetPhysicalDeviceProcAddr;
 
     return NULL;
 }
@@ -289,6 +296,18 @@
     return pTable->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    layer_data *my_data;
+    my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
+
+    if (pTable->GetPhysicalDeviceProcAddr == NULL)
+        return NULL;
+    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 VKAPI_ATTR VkResult VKAPI_CALL
 CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
                              const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
@@ -446,3 +465,27 @@
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
     return threading::GetInstanceProcAddr(instance, funcName);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return threading::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        threading::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/unique_objects.cpp b/layers/unique_objects.cpp
index df03daa..dabdc04 100644
--- a/layers/unique_objects.cpp
+++ b/layers/unique_objects.cpp
@@ -51,6 +51,8 @@
 
 namespace unique_objects {
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static void initUniqueObjects(layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
     layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "google_unique_objects");
 }
@@ -262,11 +264,17 @@
                                                    1,                    // implementationVersion
                                                    "Google Validation Layer"};
 
+/// Declare prototype for these functions
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
+
 static inline PFN_vkVoidFunction layer_intercept_proc(const char *name) {
     for (unsigned int i = 0; i < sizeof(procmap) / sizeof(procmap[0]); i++) {
         if (!strcmp(name, procmap[i].name))
             return procmap[i].pFunc;
     }
+    if (0 == strcmp(name, "vk_layerGetPhysicalDeviceProcAddr")) {
+        return (PFN_vkVoidFunction)GetPhysicalDeviceProcAddr;
+    }
     return NULL;
 }
 
@@ -337,6 +345,17 @@
     return disp_table->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkLayerInstanceDispatchTable *disp_table = instance_data->instance_dispatch_table;
+    if (disp_table->GetPhysicalDeviceProcAddr == NULL) {
+        return NULL;
+    }
+    return disp_table->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 VKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
                                               const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
     const VkMemoryAllocateInfo *input_allocate_info = pAllocateInfo;
@@ -749,3 +768,27 @@
     assert(physicalDevice == VK_NULL_HANDLE);
     return unique_objects::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return unique_objects::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        unique_objects::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/layers/vk_layer_table.cpp b/layers/vk_layer_table.cpp
index d9ec3c5..bc9062e 100644
--- a/layers/vk_layer_table.cpp
+++ b/layers/vk_layer_table.cpp
@@ -155,6 +155,10 @@
 
     layer_init_instance_dispatch_table(instance, pTable, gpa);
 
+    // Setup func pointers that are required but not externally exposed.  These won't be added to the instance dispatch table by
+    // default.
+    pTable->GetPhysicalDeviceProcAddr = (PFN_GetPhysicalDeviceProcAddr)gpa(instance, "vk_layerGetPhysicalDeviceProcAddr");
+
     return pTable;
 }
 
diff --git a/layers/windows/VkLayer_core_validation.json b/layers/windows/VkLayer_core_validation.json
index f98be95..dff857f 100644
--- a/layers/windows/VkLayer_core_validation.json
+++ b/layers/windows/VkLayer_core_validation.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_core_validation",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_core_validation.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_image.json b/layers/windows/VkLayer_image.json
index afc4205..de1ae7e 100644
--- a/layers/windows/VkLayer_image.json
+++ b/layers/windows/VkLayer_image.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_image",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_image.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_object_tracker.json b/layers/windows/VkLayer_object_tracker.json
index 5a9d966..4f64872 100644
--- a/layers/windows/VkLayer_object_tracker.json
+++ b/layers/windows/VkLayer_object_tracker.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_object_tracker",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_object_tracker.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_parameter_validation.json b/layers/windows/VkLayer_parameter_validation.json
index a3ca313..8704672 100644
--- a/layers/windows/VkLayer_parameter_validation.json
+++ b/layers/windows/VkLayer_parameter_validation.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_parameter_validation",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_parameter_validation.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_swapchain.json b/layers/windows/VkLayer_swapchain.json
index 527f107..9715996 100644
--- a/layers/windows/VkLayer_swapchain.json
+++ b/layers/windows/VkLayer_swapchain.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_swapchain",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_swapchain.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "LunarG Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_threading.json b/layers/windows/VkLayer_threading.json
index ffb0c97..c9cd979 100644
--- a/layers/windows/VkLayer_threading.json
+++ b/layers/windows/VkLayer_threading.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_GOOGLE_threading",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_threading.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "Google Validation Layer",
         "instance_extensions": [
diff --git a/layers/windows/VkLayer_unique_objects.json b/layers/windows/VkLayer_unique_objects.json
index b46fa20..8f55bac 100644
--- a/layers/windows/VkLayer_unique_objects.json
+++ b/layers/windows/VkLayer_unique_objects.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_GOOGLE_unique_objects",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_unique_objects.dll",
-        "api_version": "1.0.38",
+        "api_version": "1.0.39",
         "implementation_version": "1",
         "description": "Google Validation Layer"
     }
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index 800e80b..ba3abad 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -13,7 +13,7 @@
     endif()
 
     if (BUILD_WSI_XLIB_SUPPORT)
-       add_definitions(-DVK_USE_PLATFORM_XLIB_KHR)
+       add_definitions(-DVK_USE_PLATFORM_XLIB_KHR -DVK_USE_PLATFORM_XLIB_XRANDR_EXT)
     endif()
 
     if (BUILD_WSI_WAYLAND_SUPPORT)
@@ -61,6 +61,7 @@
 
 set (OPT_LOADER_SRCS
     dev_ext_trampoline.c
+    phys_dev_ext.c
 )
 
 set (LOADER_SRCS ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS})
@@ -110,7 +111,7 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith")
 
     add_library(${API_LOWERCASE} SHARED ${LOADER_SRCS})
-    set_target_properties(${API_LOWERCASE} PROPERTIES SOVERSION "1" VERSION "1.0.38")
+    set_target_properties(${API_LOWERCASE} PROPERTIES SOVERSION "1" VERSION "1.0.39")
     target_link_libraries(${API_LOWERCASE} -ldl -lpthread -lm)
     install(TARGETS ${API_LOWERCASE} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
 endif()
diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md
index c3492d3..9891b29 100644
--- a/loader/LoaderAndLayerInterface.md
+++ b/loader/LoaderAndLayerInterface.md
@@ -1,153 +1,381 @@
-# Vulkan Loader Specification and Architecture Overview
+# Architecture of the Vulkan Loader Interfaces
 
-<br/>
+## Table of Contents
+ * [Overview](#overview)
+  * [Who Should Read This Document](#who-should-read-this-document)
+  * [The Loader](#the-loader)
+  * [Layers](#layers)
+  * [Installable Client Drivers](#installable-client-drivers)
+  * [Instance Versus Device](#instance-versus-device)
+  * [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains)
 
-## Goals of this document ##
+ * [Application Interface to the Loader](#application-interface-to-the-loader)
+  * [Interfacing with Vulkan Functions](#interfacing-with-vulkan-functions)
+  * [Application Layer Usage](#application-layer-usage)
+  * [Application Usage of Extensions](#application-usage-of-extensions)
 
-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.
+ * [Loader and Layer Interface](#loader-and-layer-interface)
+  * [Layer Discovery](#layer-discovery)
+  * [Layer Version Negotiation](#layer-version-negotiation)
+  * [Layer Call Chains and Distributed Dispatch](#layer-call-chains-and-distributed-dispatch)
+  * [Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions)
+  * [Layer Intercept Requirements](#layer-intercept-requirements)
+  * [Distributed Dispatching Requirements](#distributed-dispatching-requirements)
+  * [Layer Conventions and Rules](#layer-conventions-and-rules)
+  * [Layer Dispatch Initialization](#layer-dispatch-initialization)
+  * [Example Code for CreateInstance](#example-code-for-createinstance)
+  * [Example Code for CreateDevice](#example-code-for-createdevice)
+  * [Special Considerations](#special-considerations)
+  * [Layer Manifest File Format](#layer-manifest-file-format)
+  * [Layer Library Versions](#layer-library-versions)
 
-<br/>
+ * [Vulkan Installable Client Driver interface with the loader](#vulkan-installable-client-driver-interface-with-the-loader)
+  * [ICD Discovery](#icd-discovery)
+  * [ICD Manifest File Format](#icd-manifest-file-format)
+  * [ICD Vulkan Entry-Point Discovery](#icd-vulkan-entry-point-discovery)
+  * [ICD Unknown Physical Device Extensions](#icd-unknown-physical-device-extensions)
+  * [ICD Dispatchable Object Creation](#icd-dispatchable-object-creation)
+  * [Handling KHR Surface Objects in WSI Extensions](#handling-khr-surface-objects-in-wsi-extensions)
+  * [Loader and ICD Interface Negotiation](#loader-and-icd-interface-negotiation)
+ * [Glossary of Terms](#glossary-of-terms)
+ 
+## Overview
 
-## Audience ##
+Vulkan is a layered architecture, made up of the following elements:
+ * The Vulkan Application
+ * [The Vulkan Loader](#the-loader)
+ * [Vulkan Layers](#layers)
+ * [Installable Client Drivers (ICDs)](#installable-client-drivers)
 
-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.
+![High Level View of Loader](./images/high_level_loader.png)
 
-<br/>
+The general concepts in this document are applicable to the loaders available
+for Windows, Linux and Android based systems.
 
 
-## Loader goals ##
+#### Who Should Read This Document
 
--   Support multiple ICDs (Installable Client Drivers) to co-exist on a system
-without interfering with each other.
+While this document is primarily targeted at developers of Vulkan applications,
+drivers and layers, the information contained in it could be useful to anyone
+wanting a better understanding of the Vulkan runtime.
 
--   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.
+#### The Loader
 
-<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.
+As you can see, the application sits on one end, and interfaces directly to the
+loader.  The loader itself can contain some number of [layers](#layers), which
+provide special functionality an application may wish to take advantage of.
+Finally, on the other end of the loader from the application are the ICDs, which
+control the Vulkan-capable hardware.  An important point to remember is that
+Vulkan-capable hardware can be graphics-based, compute-based, or both.
 
 The loader is responsible for working with the various layers as well as
-supporting multiple GPUs and their drivers.  Any Vulkan command may
+supporting multiple GPUs and their drivers.  Any Vulkan function 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
+functions 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.
+can process Vulkan functions prior to the ICD being called.
+
+This document is intended to provide an overview of the necessary interfaces
+between each of these.
+
+
+##### Goals of the Loader
+
+The loader was designed with the following goals in mind.
+ 1. Support one or more Vulkan-capable ICD on a user's computer system without
+them interfering with one another.
+ 2. Support Vulkan Layers which are optional modules that can be enabled by an
+application, developer, or standard system settings.
+ 3. Impact the overall performance of a Vulkan application in the lowest
+possible fashion.
+
+
+#### Layers
+
+Layers are optional components that augment the Vulkan system.  They can
+intercept, evaluate, and modify existing Vulkan functions on their way from the
+application down to the hardware.  Layers are implemented as libraries that can
+be enabled in different ways (including by application request) and are loaded
+during CreateInstance.  Each layer can choose to hook (intercept) any Vulkan
+functions which in turn can be ignored or augmented.  A layer does not need to
+intercept all Vulkan functions.  It may choose to intercept all known functions,
+or, it may choose to intercept only one function.
+
+Some examples of features that layers may expose include:
+ * Validating API usage
+ * Adding the ability to perform Vulkan API tracing and debugging
+ * Overlay additional content on the applications surfaces
+
+Because layers are optionally, you may choose to enable layers for debugging
+your application, but then disable any layer usage when you release your
+product.
+
+
+#### Installable Client Drivers
+
+Vulkan allows multiple Installable Client Drivers (ICDs) each supporting 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.
+
+
+#### Instance Versus Device
+
+There is an important concept which you will see brought up repeatedly
+throughout this document.  Many functions, extensions, and other things in
+Vulkan are separated into two main groups:
+ * Instance-related Objects
+ * Device-related Objects
+
+
+##### Instance-related Objects
+
+A Vulkan Instance is a high-level construct used to provide Vulkan system-level
+information, or functionality.  Vulkan objects associated directly with an
+instance are:
+ * `VkInstance`
+ * `VkPhysicalDevice`
+
+An Instance function is any Vulkan function which takes as its first parameter
+either an object from the Instance list, or nothing at all.  Some Vulkan
+Instance functions are:
+ * `vkEnumerateInstanceExtensionProperties`
+ * `vkEnumeratePhysicalDevices`
+ * `vkCreateInstance`
+ * `vkDestroyInstance`
+
+You query Vulkan Instance functions using `vkGetInstanceProcAddr`.
+`vkGetInstanceProcAddr` can be used to query either device or instance entry-
+points in addition to all core entry-points.  The returned function pointer is
+valid for this Instance and any object created under this Instance (including
+all `VkDevice` objects).  
+
+Similarly, an Instance extension is a set of Vulkan Instance functions extending
+the Vulkan language.  These will be discussed in more detail later.
+
+
+##### Device-related Objects
+
+A Vulkan Device, on the other-hand, is a logical identifier used to associate
+functions with a particular physical device on a user's system.  Vulkan
+constructs associated directly with a device include:
+ * `VkDevice`
+ * `VkQueue`
+ * `VkCommandBuffer`
+ * Any dispatchable object that is a child of a one of the above.
+
+A Device function is any Vulkan function which takes any Device Object as its
+first parameter.  Some Vulkan Device functions are:
+ * `vkQueueSubmit`
+ * `vkBeginCommandBuffer`
+ * `vkCreateEvent`
+
+You can query Vulkan Device functions using either `vkGetInstanceProcAddr` or 
+`vkGetDeviceProcAddr`.  If you choose to use `vkGetInstanceProcAddr`, it will
+have an additional level built into the call chain, which will reduce
+performance slightly.  However, the function pointer returned can be used for
+any device created later, as long as it is associated with the same Vulkan
+Instance. If, instead you use `vkGetDeviceProcAddr`, the call chain will be more
+optimized to the specific device, but it will **only** work for the device used
+to query the function function pointer.  Also, unlike `vkGetInstanceProcAddr`,
+`vkGetDeviceProcAddr` can only be used on core Vulkan Device functions, or
+Device extension functions.
+
+The best solution is to query Instance extension functions using
+`vkGetInstanceProcAddr`, and to query Device extension functions using
+`vkGetDeviceProcAddr`.  See
+[Best Application Performance Setup](#best-application-performance-setup) for
+more information on this.
+
+As with Instance extensions, a Device extension is a set of Vulkan Device
+functions extending the Vulkan language. You can read more about these later in
+the document.
+
+
+#### Dispatch Tables and Call Chains
 
 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.
+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
+ - Instance Dispatch Table
+  - Created in the loader during the call to `vkCreateInstance`
+ - Device Dispatch Table
+  - Created in the loader during the call to `vkCreateDevice`
 
-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.
+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.
+
+When an application calls a Vulkan function, this typically will first hit a
+*trampoline* function in the loader.  These *trampoline* functions are small,
+simple functions that jump to the appropriate dispatch table entry for the
+object they are given.  Additionally, for functions in the instance call chain,
+the loader has an additional function, called a *terminator*, which is called
+after all enabled layers to marshall the appropriate information to all
+available ICDs.
+
+
+##### Instance Call Chain Example
 
 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
+`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.
-![Instance call chain](instance_call_chain.png)
+what it needs based on the `VkInstanceCreateInfo` structure from the
+application.
+
+![Instance Call Chain](./images/loader_instance_chain.png)
 
 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.
+instance call chains. As shown here, the loader's *terminator* must aggregate
+information to and from multiple ICDs when they are present. This implies that
+the loader has to be aware of any instance-level extensions which work on a
+`VkInstance` 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.
-![Chain skipping layers](chain_skipping_layers.png)
+
+##### Device Call Chain Example
+
+Device call 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. 
+
+![Loader Device Call Chain](./images/loader_device_chain_loader.png)
+
 
 <br/>
+<br/>
 
-## Application interface to loader ##
+## Application Interface to the Loader
 
-In this section we'll discuss how an application interacts with the loader.
+In this section we'll discuss how an application interacts with the loader,
+including:
+ * [Interfacing with Vulkan Functions](#interfacing-with-vulkan-functions)
+  * [Vulkan Direct Exports](#vulkan-direct-exports)
+  * [Indirectly Linking to the Loader](#indirectly-linking-to-the-loader)
+  * [Best Application Performance Setup](#best-application-performance-setup)
+  * [ABI Versioning](#abi-versioning)
+ * [Application Layer Usage](#application-layer-usage)
+  * [Implicit vs Explicit Layers](#implicit-vs-explicit-layers)
+  * [Forcing Layer Source Folders](#forcing-layer-source-folders)
+  * [Forcing Layers to be Enabled](#forcing-layers-to-be-enabled)
+  * [Overall Layer Ordering](#overall-layer-ordering)
+ * [Application Usage of Extensions](#application-usage-of-extensions)
+  * [Instance and Device Extensions](#instance-and-device-extensions)
+  * [WSI Extensions](#wsi-extensions)
+  * [Unknown Extensions](#unknown-extensions)  
 
--   Linking to loader library for core and WSI extension symbols.
+  
+#### Interfacing with Vulkan Functions
+There are several ways you can interface with Vulkan functions through the
+loader.
 
--   Dynamic Vulkan command lookup & application dispatch table.
 
--   Loader library filenames for linking to different Vulkan ABI versions.
-
--   Layers
-
--   Extensions
-
--   vkGetInstanceProcAddr, vkGetDeviceProcAddr
-
+##### Vulkan Direct Exports
 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
+*trampoline* functions that jump to the appropriate dispatch table entry for the
 object they are given.
 
+
+##### Indirectly Linking to the Loader
 Applications are not required to link directly to the loader library, instead
 they can use the appropriate platform specific dynamic symbol lookup on the
 loader library to initialize the application's own dispatch table. This allows
-an application to fail gracefully if the loader cannot be found, and it
+an application to fail gracefully if the loader cannot be found.  It also
 provides the fastest mechanism for the application to call Vulkan functions. An
 application 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.
+address of `vkGetInstanceProcAddr` from the loader library. Using
+`vkGetInstanceProcAddr` the application can then discover the address of all
+functions and extensions available, such as `vkCreateInstance`,
+`vkEnumerateInstanceExtensionProperties` and
+`vkEnumerateInstanceLayerProperties` in a platform-independent way.
 
+
+##### Best Application Performance Setup
+
+If you desire the best performance possible, you should setup your own
+dispatch table so that all your Instance functions are queried using
+`vkGetInstanceProcAddr` and all your Device functions are queried using
+`vkGetDeviceProcAddr`.
+
+*Why should you do this?*
+
+The answer comes in how the call chain of Instance functions are implemented
+versus the call chain of a Device functions.  Remember, a [Vulkan Instance is a
+high-level construct used to provide Vulkan system-level information](#instance-
+related-objects). Because of this, Instance functions need to be broadcasted to
+every available ICD on the system.  The following diagram shows an approximate
+view of an Instance call chain with 3 enabled layers:
+
+![Instance Call Chain](./images/loader_instance_chain.png)
+
+This is also how a Vulkan Device function call chain looks if you query it
+using `vkGetInstanceProcAddr`.  On the otherhand, a Device
+function doesn't need to worry about the broadcast becuase it knows specifically
+which associated ICD and which associated Physical Device the call should
+terminate at.  Because of this, the loader doesn't need to get involved between
+any enabled layers and the ICD.  Thus, if you used a loader-exported Vulkan
+Device function, the call chain in the same scenario as above would look like:
+
+![Loader Device Call Chain](./images/loader_device_chain_loader.png)
+
+An even better solution would be for an application to perform a
+`vkGetDeviceProcAddr` call on all Device functions.  This further optimizes the
+call chain by removing the loader all-together under most scenarios:
+
+![Application Device Call Chain](./images/loader_device_chain_app.png)
+
+Also, notice if no layers are enabled, your application function pointer would
+point **directly to the ICD**.  If called enough, those fewer calls can add up
+to performance savings.
+
+**NOTE:** There are some Device functions which still require the loader to
+intercept them with a *trampoline* and *terminator*. There are very few of
+these, but they are typically functions which the loader wraps with its own
+data.  In those cases, even the Device call chain will continue to look like the
+Instance call chain.  One example of a Device function requiring a *terminator*
+is `vkCreateSwapchainKHR`.  For that function, the loader needs to potentially
+convert the KHR_surface object into an ICD-specific KHR_surface object prior to
+passing down the rest of the function's information to the ICD.
+
+Remember:
+ * `vkGetInstanceProcAddr` can be used to query
+either device or instance entry-points in addition to all core entry-points.
+ * `vkGetDeviceProcAddr` can only be used to query for device
+extension or core device entry-points.
+
+
+##### ABI Versioning
 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).
+SDKs, OS package distributions and Independent Hardware Vendor (IHV) driver
+packages. These details are beyond the scope of this document. However, the name
+and versioning of the Vulkan loader library is specified so an app can link to
+the correct Vulkan ABI library version. 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
@@ -155,70 +383,99 @@
 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
+
+#### Application 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.
+use various layers or extensions. A layer cannot introduce new Vulkan core API
+entry-points to an application that are not exposed in Vulkan.h.  However,
+layers may offer extensions that introduce new Vulkan commands that can be
+queried through the extension interface.
 
-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
+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.
+
+To find out what layers are available to your application, use
+`vkEnumerateInstanceLayerProperties`.  This will report all layers
+that have been discovered by the loader.  The loader looks in various locations
+to find layers on the system.  For more information see the
+[Layer discovery](#layer-discovery) section below.
+
+To enable a layer, or layers, simply pass the name of the layers you wish to
+enable in the `ppEnabledLayerNames` field of the `VkInstanceCreateInfo` during
+a call to `vkCreateInstance`.  Once done, the layers you have enabled will be
+active for all Vulkan functions using the created `VkInstance`, and any of
+its child objects.
+
+**NOTE:** Layer ordering is important in several cases since some layers
+interact with each other.  Be careful when enabling layers as this may be
+the case.  See the [Overall Layer Ordering](#overall-layer-ordering) section
+for more information.
+
+The following code section shows how you would go about enabling the
+VK_LAYER_LUNARG_standard_validation layer.
+
+```
+   char *instance_validation_layers[] = {
+        "VK_LAYER_LUNARG_standard_validation"
+    };
+    const VkApplicationInfo app = {
+        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+        .pNext = NULL,
+        .pApplicationName = "TEST_APP",
+        .applicationVersion = 0,
+        .pEngineName = "TEST_ENGINE",
+        .engineVersion = 0,
+        .apiVersion = VK_API_VERSION_1_0,
+    };
+    VkInstanceCreateInfo inst_info = {
+        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+        .pNext = NULL,
+        .pApplicationInfo = &app,
+        .enabledLayerCount = 1,
+        .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
+        .enabledExtensionCount = 0,
+        .ppEnabledExtensionNames = NULL,
+    };
+    err = vkCreateInstance(&inst_info, NULL, &demo->inst);
+```
+
+At `vkCreateInstance` and `vkCreateDevice`, the loader constructs call chains
+that include the application specified (enabled) layers.  Order is important in
+the `ppEnabledLayerNames` array; array element 0 is the topmost (closest to the
 application) layer inserted in the chain and the last array element is closest
-to the driver.
+to the driver.  See the [Overall Layer Ordering](#overall-layer-ordering)
+section for more information on layer ordering.
 
-**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.  
+**NOTE:** *Device Layers Are Now Deprecated*
+> `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`.
+> Because of this, the following items have been deprecated:
+> * `VkDeviceCreateInfo` fields:
+>  * `ppEnabledLayerNames`
+>  * `enabledLayerCount`
+> * The `vkEnumerateDeviceLayerProperties` function
 
-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.
+##### Implicit vs Explicit Layers
 
-An example of using these environment variables to activate the validation
-layer VK\_LAYER\_LUNARG\_parameter\_validation on Windows or Linux is as follows:
+Explicit layers are layers which are enabled by an application (e.g. with the
+vkCreateInstance function), or by an environment variable (as mentioned
+previously).
 
-```
-> $ 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 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.
 
 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
@@ -228,755 +485,332 @@
 On Desktop platforms (Windows and Linux), these enable/disable settings are
 defined in the layer's JSON file.
 
+Discovery of system-installed implicit and explicit layers is described later in
+the [Layer Discovery Section](#layer-discovery).  For now, simply know that what
+distinguishes a layer as implicit or explicit is dependent on the Operating
+system, as shown in the table below.
+
+| Operating System | Implicit Layer Identification |
+|----------------|--------------------|
+| Windows  | Implicit Layers are located in a different Windows registry location than Explicit Layers. |
+| Linux | Implicit Layers are located in a different directory location than Explicit Layers. |
+| Android | There is **No Support For Implicit Layers** on Android. |
+
+
+##### Forcing Layer Source Folders
+
+Developers may need to use special, pre-production layers, without modifying the
+system-installed layers. You can direct the loader to look for layers in a
+specific folder by defining the "VK\_LAYER\_PATH" environment variable.  This
+will override the mechanism used for finding system-installed layers. Because
+layers of interest may exist in several disinct folders on on a system, this
+environment variable can containis several paths seperated by the operating
+specific path separator.  On Windows, each separate folder should be separated
+in the list using a semi-colon.  On Linux, each folder name should be separated
+using a colon.
+
+If "VK\_LAYER\_PATH" exists, **only** the folders listed in it will be scanned
+for layers.  Each directory listed should be the full pathname of a folder
+containing layer manifest files.
+
+
+##### Forcing Layers to be Enabled on Windows and Linux
+
+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 top-most layer (closest to the application) and the last
+layer in the list being the bottom-most layer (closest to the driver).
+See the [Overall Layer Ordering](#overall-layer-ordering) section
+for more information.
+
+Application specified layers and user specified layers (via environment
+variables) are aggregated and duplicates removed by the loader when enabling
+layers. Layers specified via environment variable are top-most (closest to the
+application) while layers specified by the application are 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
+```
+
+
+##### Overall Layer Ordering
+
+The overall ordering of all layers by the loader based on the above looks
+as follows:
+
+![Loader Layer Ordering](./images/loader_layer_order.png)
+
+Ordering may also be important internal to the list of Explicit Layers.
+Some layers may be dependent on other behavior being implemented before
+or after the loader calls it.  For example: the VK_LAYER_LUNARG_core_validation
+layer expects the VK_LAYER_LUNARG_parameter_validation to be called first.
+This is because the VK_LAYER_LUNARG_parameter_validation will filter out any
+invalid `NULL` pointer calls prior to the rest of the validation checking
+done by VK_LAYER_LUNARG_core_validation.  If not done properly, you may see
+crashes in the VK_LAYER_LUNARG_core_validation layer that would otherwise be
+avoided.
+
+
+#### Application Usage of Extensions
+
 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.
+specified and registered with Khronos.  These extensions can be created
+by an Independent Hardware Vendor (IHV) to expose new hardware functionality,
+or by a layer writer to expose some internal feature, or by the loader to
+improve functional behavior.  Information about various extensions can be
+found in the Vulkan Spec, and vulkan.h header file.
 
-#### Instance/Device Extensions
 
-Instance extensions can be discovered via
-vkEnumerateInstanceExtensionProperties. Device extensions can be discovered via
-vkEnumerateDeviceExtensionProperties. The loader discovers and aggregates all
+##### Instance and Device Extensions
+
+As hinted at in the [Instance Versus Device](#instance-versus-device) section,
+there are really two types of extensions:
+ * Instance Extensions
+ * Device Extensions
+
+An Instance extension is an extension which modifies existing behavior or
+implements new behavior on instance-level objects, like a `VkInstance` or
+a `VkPhysicalDevice`.  A Device extension is an extension which does the same,
+but for any `VkDevice` object, or any dispatchable object that is a child of a
+`VkDevice` (`VkQueue` and `VkCommandBuffer` are examples of these).
+
+It is **very** important to know what type of extension you are desiring to
+enable as you will enable Instance extensions during `vkCreateInstance` and
+Device extensions during `vkCreateDevice`.
+
+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
+reporting them to the application in `vkEnumerateXXXExtensionProperties`
+(where XXX is either "Instance" or "Device").
+ - Instance extensions are discovered via
+`vkEnumerateInstanceExtensionProperties`.
+ - Device extensions are be discovered via
+`vkEnumerateDeviceExtensionProperties`.
+
+Looking at `vulkan.h`, you'll notice that they are both similar.  For example,
+`vkEnumerateInstanceExtensionProperties` prototype looks as follows:
+
+```
+   VkResult
+   vkEnumerateInstanceExtensionProperties(const char *pLayerName,
+                                          uint32_t *pPropertyCount,
+                                          VkExtensionProperties *pProperties);
+```
+
+The "pLayerName" parameter in these functions is used to select either a single
+layer or the Vulkan platform implementation. If "pLayerName" is NULL, extensions
+from Vulkan implementation components (including loader, implicit layers, and
+ICDs) are enumerated. If "pLayerName" is equal to a discovered layer module name
+then only extensions from that layer (which may be implicit or explicit) are
 enumerated. 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.
+support for the same extension) are eliminated by the loader. For duplicates,
+the ICD version is reported and the layer version is culled.
 
-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.
+Also, Extensions *must be enabled* (in `vkCreateInstance` or `vkCreateDevice`)
+before the functions associated with the extensions can be used.  If you get an
+Extension function using either `vkGetInstanceProcAddr` or
+`vkGetDeviceProcAddr`, but fail to enable it, you could experience undefined
+behavior.  This should actually be flagged if you run with Validation layers
+enabled.
 
-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.
-
-![Get*ProcAddr efficiency](get_proc_addr.png)
 
 ##### 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
+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 and directly exports those
+WSI extensions that are appropriate to the current environment. For the most
+part, the selection is done in the loader using compile-time preprocessor flags.
+All versions of the 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
+In addition, each of the following OS targets for the loader support target-
+specific extensions:
 
-**NOTE:** Wayland and Mir targets are not fully supported at this time and should be considered
-alpha quality.
+| Windowing System | Extensions available |
+|----------------|--------------------|
+| Windows  | VK_KHR_win32_surface |
+| Linux (Default) |  VK_KHR_xcb_surface and VK_KHR_xlib_surface |
+| Linux (Wayland) | VK_KHR_wayland_surface |
+| Linux (Mir)  | VK_KHR_mir_surface |
 
-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:
+**NOTE:** Wayland and Mir targets are not fully supported at this time.  Wayland
+support is present, but should be considered Beta quality.  Mir support is not
+completely implemented at this time.
+
+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 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.
+##### Unknown Extensions
+
+With the ability to expand Vulkan so easily, extensions will be created that the
+loader knows nothing about.  If the extension is a device extension, the loader
+will pass the unknown entry-point down the device call chain ending with the
+appropriate ICD entry-points.  The same thing will happen, if the extension is
+an instance extension which takes a physical device paramater as it's first
+component.  However, for all other instance extensions the loader will fail to
+load it.
 
 *But why doesn't the loader support unknown instance extensions?*
 <br/>
 Let's look again at the Instance call chain:
-![Instance call chain](instance_call_chain.png)
 
-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.
+![Instance call chain](./images/loader_instance_chain.png)
 
-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.
+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
+instance extensions which don't take a physical device as their first parameter.
+
+Because the device call-chain does not normally pass through the loader
+*terminator*, this is not a problem for device extensions.  Additionally,
+since a physical device is associated with one ICD, we can use a generic
+*terminator* pointing to one ICD.  This is because both of these 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/local/etc/vulkan/icd.d
-    /usr/local/share/vulkan/icd.d
-    /etc/vulkan/icd.d
-    /usr/share/vulkan/icd.d
-    $HOME/.local/share/vulkan/icd.d
-```
-
-The "/usr/local/*" directories can be configured to be other directories at build time.
-
-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/local/etc/vulkan/icd.d" and "/usr/local/share/vulkan/icd.d"
-directories are for locally-built ICDs.
-
-The "/etc/vulkan/icd.d" directory is for
-ICDs that are installed from non-Linux-distribution-provided packages.
-
-The "/usr/share/vulkan/icd.d" directory is for ICDs that are installed from
-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/local/etc/vulkan/icd.d",
-"/usr/local/share/vulkan/icd.d",
-"/etc/vulkan/icd.d",
-"/usr/share/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
+No!  Most extension functionality only affects either a physical or logical
+device and not an instance.  Thus, the overwhelming majority of extensions
+should be supported with direct loader support.
 
-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 ##
+## Loader and Layer Interface
 
-### Layer discovery
+In this section we'll discuss how the loader interacts with layers, including:
+ * [Layer Discovery](#layer-discovery)
+  * [Layer Manifest File Usage](#layer-manifest-file-usage)
+  * [Android Layer Discovery](#android-layer-discovery)
+  * [Windows Layer Discovery](#windows-layer-discovery)
+  * [Linux Layer Discovery](#linux-layer-discovery)
+ * [Layer Version Negotiation](#layer-version-negotiation)
+ * [Layer Call Chains and Distributed Dispatch](#layer-call-chains-and-distributed-dispatch)
+ * [Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions)
+ * [Layer Intercept Requirements](#layer-intercept-requirements)
+ * [Distributed Dispatching Requirements](#distributed-dispatching-requirements)
+ * [Layer Conventions and Rules](#layer-conventions-and-rules)
+ * [Layer Dispatch Initialization](#layer-dispatch-initialization)
+ * [Example Code for CreateInstance](#example-code-for-createinstance)
+ * [Example Code for CreateDevice](#example-code-for-createdevice)
+ * [Special Considerations](#special-considerations)
+  * [Associating Private Data with Vulkan Objects Within a Layer](#associating-private-data-with-vulkan-objects-within-a-layer)
+    * [Wrapping](#wrapping)
+    * [Hash Maps](#hash-maps)
+  * [Creating New Dispatchable Objects](#creating-new-dispatchable-objects)
+ * [Layer Manifest File Format](#layer-manifest-file-format)
+  * [Layer Manifest File Version History](#layer-manifest-file-version-history)
+ * [Layer Library Versions](#layer-library-versions)
+  * [Layer Library API Version 2](#layer-library-api-version-2)
+  * [Layer Library API Version 1](#layer-library-api-version-1)
+  * [Layer Library API Version 0](#layer-library-api-version-0)
+  
 
-#### Windows
+ 
+#### Layer Discovery
 
-<a name="ManifestFileExample"></a>
-##### Properly-Installed Layers
+As mentioned in the
+[Application Interface section](#implicit-vs-explicit-layers),
+layers can be categorized into two categories:
+ * Implicit Layers
+ * Explicit 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).
+The main difference between the two is that Implicit Layers are automatically
+enabled, unless overriden, and Explicit Layers must be enabled.  Remember,
+Implicit Layers are not present on all Operating Systems (like Android).
 
-In order to find properly-installed layers, the Vulkan loader will scan the
+On any system, the loader looks in specific areas for information on the
+layers that it can load at a user's request.  The process of finding the
+available layers on a system is known as Layer Discovery.  During discovery,
+the loader determines what layers are available, the layer name, the layer
+version, and any extensions supported by the layer.  This information is
+provided back to an application through `vkEnumerateInstanceLayerProperties`.
+
+The group of layers available to the loader is known as a layer library.  This
+section defines an extensible interface to discover what layers are contained in
+the layer library.
+
+This section also specifies the minimal conventions and rules a layer must
+follow, especially with regards to interacting with the loader and other layers.
+
+##### Layer Manifest File Usage
+
+On Windows and Linux systems, JSON formated manifest files are used to store
+layer information.  In order to find system-installed layers, the Vulkan loader
+will read the JSON files to identify the names and attributes of layers and
+their extensions. The use of manifest files allows the loader to avoid loading
+any shared library files when the application does not query nor request any
+extensions.  The format of [Layer Manifest File](#layer-manifest-file-format)
+is detailed below.
+
+The Android loader does not use manifest files.  Instead, the loader queries the
+layer properties using special functions known as "introspection" functions.
+The intent of these functions is to determine the same required information
+gathered from reading the manifest files.  These introspection functions are
+not used by the desktop loader but should be present in layers to maintain
+consistency.  The specific "introspection" functions are called out in
+the [Layer Manifest File Format](#layer-manifest-file-format) table.
+
+
+##### Android Layer Discovery
+
+On Android, the loader looks for layers to enumerate in the
+/data/local/debug/vulkan folder.  An application enabled for debug has the
+ability to enumerate and enable any layers in that location.
+
+
+##### Windows Layer Discovery
+
+In order to find system-installed layers, the Vulkan loader will scan the
 values in the following Windows registry keys:
 
-HKEY\_LOCAL\_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers
-
-HKEY\_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.
+```
+   HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ExplicitLayers
+   HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ImplicitLayers
+```
 
 For each value in these keys which has DWORD data set to 0, the loader opens
 the JSON manifest file specified by the name of the value. Each name must be a
-full pathname to the manifest file.
+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.  However, if VK\_LAYER\_PATH is defined, then the
+loader will instead look at the paths defined by that variable instead of using
+the information provided by these registry keys.  See
+[Forcing Layer Source Folders](#forcing-layer-source-folders) for more
+information on this.
 
-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.
+##### Linux Layer Discovery
 
-```
-{
-   "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:
+On Linux, the Vulkan loader will scan the files in the following Linux
+directories:
 
     /usr/local/etc/vulkan/explicit_layer.d
     /usr/local/etc/vulkan/implicit_layer.d
@@ -989,452 +823,404 @@
     $HOME/.local/share/vulkan/explicit_layer.d
     $HOME/.local/share/vulkan/implicit_layer.d
 
-The "/usr/local/*" directories can be configured to be other directories at build time.
-
-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/local/etc/vulkan/\*\_layer.d" and "/usr/local/share/vulkan/\*\_layer.d"
-directories are for layers that are installed from locally-built sources.
-
-The "/etc/vulkan/\*\_layer.d" directories are for layers that are installed from
-non-Linux-distribution-provided packages.
-
-The "/usr/share/vulkan/\*\_layer.d" directories are for layers that are
+Of course, ther are some things you have to know about the above folders:
+ 1. The "/usr/local/*" directories can be configured to be other directories at
+build time.
+ 2. $HOME is the current home directory of the application's user id; this path
+will be ignored for suid programs.
+ 3. The "/usr/local/etc/vulkan/\*\_layer.d" and
+"/usr/local/share/vulkan/\*\_layer.d" directories are for layers that are
+installed from locally-built sources.
+ 4. The "/usr/share/vulkan/\*\_layer.d" directories are for layers that are
 installed from 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.
+As on Windows, if VK\_LAYER\_PATH is defined, then the
+loader will instead look at the paths defined by that variable instead of using
+the information provided by these default paths.  However, these
+environment variables are only used for non-suid programs.  See
+[Forcing Layer Source Folders](#forcing-layer-source-folders) for more
+information on this.
 
+
+#### Layer Version Negotiation
+
+Now that a layer has been discovered, an application can choose to load it (or
+it is loaded by default if it is an Implicit layer).  When the loader attempts
+to load the layer, the first thing it does is attempt to negotiate the version
+of the loader to layer interface.  In order to negotiate the loader/layer
+interface version, the layer must implement the
+`vkNegotiateLoaderLayerInterfaceVersion` function.  The following information is
+provided for this interface in include/vulkan/vk_layer.h:
+
+```cpp
+  typedef enum VkNegotiateLayerStructType {
+      LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
+  } VkNegotiateLayerStructType;
+
+  typedef struct VkNegotiateLayerInterface {
+      VkNegotiateLayerStructType sType;
+      void *pNext;
+      uint32_t loaderLayerInterfaceVersion;
+      PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
+      PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
+      PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
+  } VkNegotiateLayerInterface;
+
+  VkResult vkNegotiateLoaderLayerInterfaceVersion(
+                   VkNegotiateLayerInterface *pVersionStruct);
 ```
-{
-   "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).
+You'll notice the `VkNegotiateLayerInterface` structure is similar to other
+Vulkan structures.  The "sType" field, in this case takes a new enum defined
+just for internal loader/layer interfacing use.  The valid values for "sType"
+could grow in the future, but right only havs the one value
+"LAYER_NEGOTIATE_INTERFACE_STRUCT".
 
-There are no rules about the name of the layer shared library files.
+This function (`vkNegotiateLoaderLayerInterfaceVersion`) should be exported by
+the layer so that using "GetProcAddress" on Windows or "dlsym" on Linux, should
+return a valid function pointer to it.  Once the loader has grabbed a valid
+address to the layers function, the loader will create a variable of type
+`VkNegotiateLayerInterface` and initialize it in the following ways:
+ 1. Set the structure "sType" to "LAYER_NEGOTIATE_INTERFACE_STRUCT"
+ 2. Set pNext to NULL.
+     - This is for future growth
+ 3. Set "loaderLayerInterfaceVersion" to the current version the loader desires
+to set the interface to.
+      - The minimum value sent by the loader will be 2 since it is the first
+version supporting this function.
 
-##### Using Pre-Production Layers
+The loader will then individually call each layer’s
+`vkNegotiateLoaderLayerInterfaceVersion` function with the filled out
+“VkNegotiateLayerInterface”. The layer will either accept the loader's version
+set in "loaderLayerInterfaceVersion", or modify it to the closest value version
+of the interface that the layer can support.  The value should not be higher
+than the version requested by the loader.  If the layer can't support at a
+minimum the version requested, then the layer should return an error like
+"VK_ERROR_INITIALIZATION_FAILED".  If a layer can support some version, then
+the layer should do the following:
+ 1. Adjust the version to the layer's desired version.
+ 2. The layer should fill in the function pointer values to its internal
+functions:
+    - "pfnGetInstanceProcAddr" should be set to the layer’s internal
+`GetInstanceProcAddr` function.
+    - "pfnGetDeviceProcAddr" should be set to the layer’s internal
+`GetDeviceProcAddr` function.
+    - "pfnGetPhysicalDeviceProcAddr" should be set to the layer’s internal
+`GetPhysicalDeviceProcAddr` function.
+      - If the layer supports no physical device extensions, it may set the
+value to NULL.
+      - More on this function later
+ 3. The layer should return "VK_SUCCESS"
 
-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:
+This function **SHOULD NOT CALL DOWN** the layer chain to the next layer.
+The loader will work with each layer individually.
 
-- The full pathname of a directory containing layer info files
+If the layer supports the new interface and reports version 2 or greater, then
+the loader will use the “fpGetInstanceProcAddr” and “fpGetDeviceProcAddr”
+functions from the “VkNegotiateLayerInterface” structure.  Prior to these
+changes, the loader would query each of those functions using "GetProcAddress"
+on Windows or "dlsym" on Linux.
 
-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/debug/vulkan.
-
-<br/>
-
-## Layer interface requirements ##
-
-#### Architectural interface overview
+#### Layer Call Chains and Distributed Dispatch
 
 There are two key architectural features that drive the loader to layer library
-interface: 1) separate and distinct instance and device call chains, and 2)
-distributed dispatch. First these architectural features will be described and
-then the detailed interface will be specified.
+interface:
+ 1. Separate and distinct instance and device call chains
+ 2. Distributed dispatch.
 
-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.
+You can read an overview of dispatch tables and call chains above in the
+[Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) section.
 
-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
+What's important to note here is that a layer can intercept Vulkan
+instance functions, device functions or both. For a layer to intercept instance
+functions, it must participate in the instance call chain.  For a layer to
+intercept device functions, it must participate in the device call chain.
+
+Remember, a layer does not need to intercept all instance or device functions,
+instead, it can choose to intercept only a subset of those functions.
+
+Normally, when a layer intercepts a given Vulkan function, it will call down the
+instance or device call chain as needed. The loader and all layer libraries that
 participate in a call chain cooperate to ensure the correct sequencing of calls
 from one entity to the next. This group effort for call chain sequencing is
-hereinafter referred to as distributed dispatch. In distributed dispatch, 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.
+hereinafter referred to as **distributed dispatch**.
 
-Instance level Vulkan commands are those that have the dispatchable objects
-VkInstance, or VkPhysicalDevice as the first parameter and also includes
-vkCreateInstance.
+In distributed dispatch each layer is responsible for properly calling the next
+entity in the call chain. This means that a dispatch mechanism is required for
+all Vulkan functions that a layer intercepts. If a Vulkan function is not
+intercepted by a layer, or if a layer chooses to terminate the function by not
+calling down the chain, then no dispatch is needed for that particular function.
 
-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.
+For example, if the enabled layers intercepted only certain instance functions,
+the call chain would look as follows:
+![Instance Function Chain](./images/function_instance_chain.png)
 
-#### Layer Library Interface
+Likewise, if the enabled layers intercepted only a few of the device functions,
+the call chain could look this way:
+![Device Function Chain](./images/function_device_chain.png)
 
-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.
+The loader is responsible for dispatching all core and instance extension Vulkan
+functions to the first entity in the call chain.
 
-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
+#### Layer Unknown Physical Device Extensions
+
+Originally, if the loader was called with `vkGetInstanceProcAddr`, it would
+result in the following behavior:
+ 1. The loader would check if core function:
+    - If it was, it would return the function pointer
+ 2. The loader would check if known extension function:
+    - If it was, it would return the function pointer
+ 3. If the loader knew nothing about it, it would call down using
+`GetInstanceProcAddr`
+    - If it returned non-NULL, treat it as an unknown logical device command.
+    - This meant setting up a generic trampoline function that takes in a
+VkDevice as the first parameter and adjusting the dispatch table to call the
+ICD/Layers function after getting the dispatch table from the VkDevice.
+ 4. If all the above failed, the loader would return NULL to the application.
+
+This caused problems when a layer attempted to expose new physical device
+extensions the loader knew nothing about, but an application did.  Because the
+loader knew nothing about it, the loader would get to step 3 in the above
+process and would treat the function as an unknown logical device command.  The
+problem is, this would create a generic VkDevice trampoline function which, on
+the first call, would attempt to dereference the VkPhysicalDevice as a VkDevice.
+This would lead to a crash or corruption.
+
+In order to identify the extension entry-points specific to physical device
+extensions, the following function can be added to a layer:
+
+```cpp
+PFN_vkVoidFunction vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
+                                                     const char* pName);
+```
+
+This function behaves similar to `vkGetInstanceProcAddr` and
+`vkGetDeviceProcAddr` except it should only return values for physical device
+extension entry-points.  In this way, it compares "pName" to every physical
+device function supported in the layer.
+
+The following rules apply:
+ * If it is the name of a physical device function supported by the layer, the
+pointer to the layer's corresponding function should be returned.
+ * If it is the name of a valid function which is **not** a physical device
+function (i.e. an Instance, Device, or other function implemented by the layer),
+then the value of NULL should be returned.
+   * We don’t call down since we know the command is not a physical device
+extension).
+ * If the layer has no idea what this function is, it should call down the layer
+chain to the next `vk_layerGetPhysicalDeviceProcAddr` call.
+   * This can be retrieved in one of two ways:
+     * During `vkCreateInstance`, it is passed to a layer in the
+chain information passed to a layer in the `VkLayerInstanceCreateInfo`
+structure.
+        * Use `get_chain_info()` to get the pointer to the
+`VkLayerInstanceCreateInfo` structure.  Let's call it chain_info.
+        * The address is then under
+chain_info->u.pLayerInfo->pfnNextGetPhysicalDeviceProcAddr
+        * See
+[Example Code for CreateInstance](#example-code-for-createinstance)
+     * Using the next layer’s `GetInstanceProcAddr` function to query for
+`vk_layerGetPhysicalDeviceProcAddr`.
+
+This support is optional and should not be considered a requirement.  This is
+only required if a layer intends to support some functionality not directly
+supported by loaders released in the public.  If a layer does implent this
+support, it should return the address of its `vk_layerGetPhysicalDeviceProcAddr`
+function in the "pfnGetPhysicalDeviceProcAddr" member of the
+`VkNegotiateLayerInterface` structure during
+[Layer Version Negotiation](#layer-version-negotiation).  Additionally, the
+layer should also make sure `vkGetInstanceProcAddr` returns a valid function
+pointer to a query of `vk_layerGetPhysicalDeviceProcAddr`.
+
+The new behavior of the loader's `vkGetInstanceProcAddr` with support for the
+`vk_layerGetPhysicalDeviceProcAddr` function is as follows:
+ 1. Check if core function:
+    - If it is, return the function pointer
+ 2. Check if known instance or device extension function:
+    - If it is, return the function pointer
+ 3. Call the layer/ICD `GetPhysicalDeviceProcAddr`
+    - If it returns non-NULL, return a trampoline to a generic physical device
+function, and setup a generic terminator which will pass it to the proper ICD.
+ 4. Call down using `GetInstanceProcAddr`
+    - If it returns non-NULL, treat it as an unknown logical device command.
+This means setting up a generic trampoline function that takes in a VkDevice as
+the first parameter and adjusting the dispatch table to call the ICD/Layers
+function after getting the dispatch table from the VkDevice. Then, return the
+pointer to corresponding trampoline function.
+ 5. Return NULL
+
+You can see now, that, if the command gets promoted to core later, it will no
+longer be setup using `vk_layerGetPhysicalDeviceProcAddr`.  Additionally, if the
+loader adds direct support for the extension, it will no longer get to step 3,
+because step 2 will return a valid function pointer.  However, the layer should
+continue to support the command query via `vk_layerGetPhysicalDeviceProcAddr`,
+until at least a Vulkan version bump, because an older loader may still be
+attempting to use the commands.
+
+
+#### Layer Intercept Requirements
+
+ * Layers intercept a Vulkan function by defining a C/C++ function with
+signature **identical** to the Vulkan API for that function.
+ * A layer **must intercept at least** `vkGetInstanceProcAddr` and
+`vkCreateInstance` to participate in the instance call chain.
+ * A layer **may also intercept** `vkGetDeviceProcAddr` and `vkCreateDevice`
+to participate in the device call chain.
+ * For any Vulkan function a layer intercepts which has a non-void return value,
+**an appropriate value must be returned** by the layer intercept function.
+ * Most functions a layer intercepts **should call down the chain** to the
+corresponding Vulkan function in the next entity.
+  * The common behavior for a layer is to intercept a call, perform some
+behavior, then pass it down to the next entity.
+    * If you don't pass the information down, undefined behavior may occur.
+    * This is because the function will not be received by layers further down
+the chain, or any ICDs.
+  * One function that **must never call down the chain** is:
+    * `vkNegotiateLoaderLayerInterfaceVersion`
+  * Three common functions that **may not call down the chain** are:
+    * `vkGetInstanceProcAddr`
+    * `vkGetDeviceProcAddr`
+    * `vk_layerGetPhysicalDeviceProcAddr`
+    * These functions only call down the chain for Vulkan functions that they
+do not intercept.
+ * Layer intercept functions **may insert extra calls** to Vulkan functions in
+addition to the intercept.
+  * For example, a layer intercepting `vkQueueSubmit` may want to add a call to
+`vkQueueWaitIdle` after calling down the chain for `vkQueueSubmit`.
+  * This would result in two calls down the chain: First a call down the
+`vkQueueSubmit` chain, followed by a call down the `vkQueueWaitIdle` chain.
+  * Any additional calls inserted by a layer must be on the same chain
+    * If the function is a device function, only other device functions should
+be added.
+    * Likewise, if the function is an instance function, only other instance
+functions should be added.
+
+
+#### Distributed Dispatching Requirements
+
+- For each entry-point a layer intercepts, it must keep track of the entry
+point residing in the next entity in the chain it will call down into.
+ * In other words, the layer must have a list of pointers to functions of the
+appropriate type to call into the next entity.
+ * This can be implemented in various ways but
+for clarity, will be referred to as a dispatch table.
+- A layer can use the `VkLayerDispatchTable` structure as a device dispatch
+table (see include/vulkan/vk_layer.h).
+- A layer can use the `VkLayerInstanceDispatchTable` structure as a instance
+dispatch table (see include/vulkan/vk_layer.h).
+- A Layer's `vkGetInstanceProcAddr` function uses the next entity's
+`vkGetInstanceProcAddr` to call down the chain for unknown (i.e.
+non-intercepted) functions.
+- A Layer's `vkGetDeviceProcAddr` function uses the next entity's
+`vkGetDeviceProcAddr` to call down the chain for unknown (i.e. non-intercepted)
+functions.
+- A Layer's `vk_layerGetPhysicalDeviceProcAddr` function uses the next entity's
+`vk_layerGetPhysicalDeviceProcAddr` to call down the chain for unknown (i.e.
+non-intercepted) functions.
+
+
+#### Layer Conventions and Rules
 
 A layer, when inserted into an otherwise compliant Vulkan implementation, must
-still result in a compliant Vulkan implementation[\*].  It must additionally
-follow some conventions and rules.
+still result in a compliant Vulkan implementation.  The intention is for layers
+to have a well-defined baseline behavior.  Therefore, it must follow some
+conventions and rules defined below.
 
 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
+to, or rely on undefined behaviors of, its lower layers.  When it changes the
+behavior of a function, it must make sure its upper layers do not make invalid
 calls to or rely on undefined behaviors of its lower layers because of the
 changed behavior.  For example, when a layer intercepts an object creation
-command to wrap the objects created by its lower layers, it must make sure its
+function to wrap the objects created by its lower layers, it must make sure its
 lower layers never see the wrapping objects, directly from itself or
 indirectly from its upper layers.
 
 When a layer requires host memory, it may ignore the provided allocators.  It
 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.
+environment.  For example, this usually applies to implicit layers that are
+always enabled.  That will allow applications to include the layer's memory
+usage.
 
-`vkEnumerateInstanceLayerProperties` must enumerate and only enumerate the
-layer itself.
+Additional rules include:
+ - `vkEnumerateInstanceLayerProperties` **must** enumerate and **only**
+enumerate the layer itself.
+ - `vkEnumerateInstanceExtensionProperties` **must** handle the case where
+`pLayerName` is itself.
+  - It **must** return `VK_ERROR_LAYER_NOT_PRESENT` otherwise, including when
+`pLayerName` is `NULL`.
+ - `vkEnumerateDeviceLayerProperties` **is deprecated and may be omitted**.
+  - Using this will result in undefined behavior.
+ - `vkEnumerateDeviceExtensionProperties` **must** handle the case where
+`pLayerName` is itself.
+  - In other cases, it should 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 function by returning a local
+entry-point
+  - Otherwise it returns the value obtained by calling down the instance call
+chain.
+ - `vkGetDeviceProcAddr` intercepts a Vulkan function by returning a local
+entry-point
+  - Otherwise it returns the value obtained by calling down the device call
+chain.
+  - These additional functions must be intercepted if the layer implements
+device-level call chaining:
+   - `vkGetDeviceProcAddr`
+   - `vkCreateDevice`(only required for any device-level chaining)
+     - **NOTE:** older layer libraries may expect that `vkGetInstanceProcAddr`
+ignore `instance` when `pName` is `vkCreateDevice`.
+ - The specification **requires** `NULL` to be returned from
+`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` for disabled functions.
+  - A layer may return `NULL` itself or rely on the following layers to do so.
 
-`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.
+#### Layer Dispatch Initialization
 
-`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
+- A layer initializes its instance dispatch table within its `vkCreateInstance`
 function.
-- A layer initializes its device dispatch table within its vkCreateDevice
+- 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
+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.
+`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.
+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
+  - 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
+  - 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
+  - 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
+  - Call down the chain either `vkCreateDevice` or `vkCreateInstance`
   - Initialize your layer dispatch table by calling the next entity's
-Get*ProcAddr function once for each Vulkan command needed in your dispatch
+Get*ProcAddr function once for each Vulkan function needed in your dispatch
 table
 
-##### Example code for CreateInstance
+#### Example Code for CreateInstance
 
 ```cpp
 VkResult vkCreateInstance(
@@ -1475,7 +1261,7 @@
 }
 ```
 
-##### Example code for CreateDevice
+#### Example Code for CreateDevice
 
 ```cpp
 VkResult 
@@ -1518,31 +1304,35 @@
 }
 ```
 
+
 #### Special Considerations
-##### Associating private data with Vulkan objects within a layer
+
+
+##### 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.
+###### Wrapping
 
-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
+The loader supports layers wrapping any Vulkan object, including dispatchable
+objects.  For functions that return object handles, each layer does not touch
+the value passed down the call chain.  This is because lower items may need to
+use the original value.  However, when the value is returned from a
+lower-level layer (possibly the ICD), the layer saves the handle  and returns
+its own handle to the layer above it (possibly the application).  When a layer
+receives a Vulkan function using something that it previously returned a handle
+for, the layer is required to unwrap the handle and pass along the saved handle
+to the layer below it.  This means that the layer **must intercept every Vulkan
+function which uses the object in question**, and wrap or unwrap the object, as
+appropriate.  This includes adding support for all extensions with functions
 using any object the layer wraps.
 
 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:
+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;
@@ -1560,15 +1350,15 @@
 Layers that wrap dispatchable objects must follow the guidelines for creating
 new dispatchable objects (below).
 
-<u><b>Cautions</b></u>
+<u>Cautions About Wrapping</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.
+that a layer wraps `VkImage` objects, and properly wraps and unwraps `VkImage`
+object handles for all core functions.  If a new extension is created which has
+functions that take `VkImage` objects as parameters, and if the layer does not
+support those new functions, an application that uses both the layer and the new
+extension will have undefined behavior when those new functions are called (e.g.
 the application may crash).  This is 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.
@@ -1584,49 +1374,904 @@
 unsupported extensions, alerting the user to the potential for undefined
 behavior.
 
-###### Hash Maps:
+
+###### 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.
+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
+
+##### Creating New Dispatchable Objects
+
+Layers which create dispatchable objects must take special care. Remember that
+loader *trampoline* code normally fills in the dispatch table pointer in the
+newly created object. Thus, the layer must fill in the dispatch table pointer if
+the loader *trampoline* will not do so.  Common cases where a layer (or ICD) may
+create a dispatchable object without loader *trampoline* code is as follows:
+- layers that wrap dispatchable objects
 - layers which add extensions that create dispatchable objects
-- layers which insert extra Vulkan commands in the stream of commands they
+- layers which insert extra Vulkan funnctions in the stream of functions 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
+The desktop 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):
+pNext field in the create info structure when creating an instance
+(`VkInstanceCreateInfo`) or device (`VkDeviceCreateInfo`).  The callback
+prototype is defined as follows for instance and device callbacks respectively
+(see `vk_layer.h`):
+
+```cpp
+VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceLoaderData(VkInstance instance,
+                                                       void *object);
+VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceLoaderData(VkDevice device,
+                                                     void *object);
 ```
-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".
+pointed to by the "pNext" field in the `VkInstanceCreateInfo` and
+`VkDeviceCreateInfo` parameters to find any callback structures inserted by the
+loader. The salient details are as follows:
+- For `VkInstanceCreateInfo` the callback structure pointed to by "pNext" is
+`VkLayerInstanceCreateInfo` as defined in `include/vulkan/vk_layer.h`.
+- A "sType" field in of VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO within
+`VkInstanceCreateInfo` parameter indicates a loader structure.
+- Within `VkLayerInstanceCreateInfo`, the "function" field indicates how the
+union field "u" should be interpreted.
+- A "function" equal to VK_LOADER_DATA_CALLBACK indicates the "u" field will
+contain the callback in "pfnSetInstanceLoaderData".
+- For `VkDeviceCreateInfo` the callback structure pointed to by "pNext" is
+`VkLayerDeviceCreateInfo` as defined in `include/vulkan/vk_layer.h`.
+- A "sType" field in of VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO within
+`VkDeviceCreateInfo` parameter indicates a loader structure.
+- Within `VkLayerDeviceCreateInfo`, the "function" field indicates how the union
+field "u" should be interpreted.
+- A "function" equal to VK_LOADER_DATA_CALLBACK indicates the "u" field will
+contain the callback in "pfnSetDeviceLoaderData".
 
-Alternatively, if an older loader is being used that doesn't provide these callbacks, the layer may manually initialize the newly created dispatchable object.
-To fill in the dispatch table pointer in newly created dispatchable object,
-the layer should copy the dispatch pointer, which is always the first entry in the structure, from an existing parent object of the same level (instance versus
-device). For example, if there is a newly created VkCommandBuffer object, then the dispatch pointer from the VkDevice object, which is the parent of the VkCommandBuffer object, should be copied into the newly created object.
+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.
+
+
+#### Layer Manifest File Format
+
+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.  This is to reduce the likelihood of
+loading a malicious layer into memory.  Instead, details are read from the
+Manifest file, which are then provided for applications to determine what
+layers should actually be loaded.
+
+The following section discusses the details of the Layer Manifest JSON file
+format.  The JSON file itself does not have any requirements for naming.  The
+only requirement is that the extension suffix of the file ends with ".json".
+
+Here is an example layer JSON Manifest file with a single layer:
+
+```
+{
+   "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": {
+           "vkNegotiateLoaderLayerInterfaceVersion":
+               "OverlayLayer_NegotiateLoaderLayerInterfaceVersion"
+       },
+       "instance_extensions": [
+           {
+               "name": "VK_EXT_debug_report",
+               "spec_version": "1"
+           },
+           {
+               "name": "VK_VENDOR_ext_x",
+               "spec_version": "3"
+            }
+       ],
+       "device_extensions": [
+           {
+               "name": "VK_EXT_debug_marker",
+               "spec_version": "1",
+               "entrypoints": ["vkCmdDbgMarkerBegin", "vkCmdDbgMarkerEnd"]
+           }
+       ],
+       "enable_environment": {
+           "ENABLE_LAYER_OVERLAY_1": "1"
+       }
+       "disable_environment": {
+           "DISABLE_LAYER_OVERLAY_1": ""
+       }
+   }
+}
+```
+
+Here's a snippet with the changes required to support multiple layers per
+manifest file:
+```
+{
+   "file_format_version" : "1.0.1",
+   "layers": [
+      {
+           "name": "VK_LAYER_layer_name1",
+           "type": "INSTANCE",
+           ...
+      },
+      {
+           "name": "VK_LAYER_layer_name2",
+           "type": "INSTANCE",
+           ...
+      }
+   ]
+}
+```
+
+| JSON Node | Description and Notes | Introspection Query |
+|:----------------:|--------------------|:----------------:
+| "file\_format\_version" | Manifest format major.minor.patch version number. | N/A |
+| | Supported versions are: 1.0.0, 1.0.1, and 1.1.0. | |
+| "layer" | The identifier used to group a single layer's information together. | vkEnumerateInstanceLayerProperties |
+| "layers" | The identifier used to group multiple layers' information together.  This requires a minimum Manifest file format version of 1.0.1.| vkEnumerateInstanceLayerProperties |
+| "name" | The string used to uniquely identify this layer to applications. | vkEnumerateInstanceLayerProperties |
+| "type" | This field indicates the type of layer.  The values can be: GLOBAL, or INSTANCE | vkEnumerate*LayerProperties |
+|  | **NOTES:** 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. |  |
+| "library\_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file.  If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file (e.g. for cases when an application provides a layer that is in the same folder hierarchy as the rest of the application files).  If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the layer shared library files other than it should end with the appropriate suffix (".DLL" on Windows, and ".so" on Linux). | N/A |
+| "api\_version" | The major.minor.patch version number of the Vulkan API that the shared library file for the library was built against. For example: 1.0.33. | vkEnumerateInstanceLayerProperties |
+| "implementation_version" | The version of the layer implemented.  If the layer itself has any major changes, this number should change so the loader and/or application can identify it properly. | vkEnumerateInstanceLayerProperties |
+| "description" | A high-level description of the layer and it's intended use. | vkEnumerateInstanceLayerProperties |
+| "functions" | **OPTIONAL:** This section can be used to identify a different function name for the loader to use in place of standard layer interface functions. The "functions" node is required if the layer is using an alternative name for `vkNegotiateLoaderLayerInterfaceVersion`. | vkGet*ProcAddr |
+| "instance\_extensions" | **OPTIONAL:** Contains the list of instance extension names supported by this layer. One "instance\_extensions" node with an array of one or more elements is required if any instance extensions are supported by a layer, otherwise the node is optional. Each element of the array must have the nodes "name" and "spec_version" which correspond to `VkExtensionProperties` "extensionName" and "specVersion" respectively. | vkEnumerateInstanceExtensionProperties |
+| "device\_extensions" | **OPTIONAL:** Contains the list of device extension names supported by this layer. One "device_\extensions" node with an array of one or more elements is required if any device extensions are supported by a layer, otherwise the node is optional. Each element of the array must have the nodes "name" and "spec_version" which correspond to `VkExtensionProperties` "extensionName" and "specVersion" respectively. Additionally, each element of the array of device extensions must have the node "entrypoints" if the device extension adds Vulkan API functions, otherwise this node is not required. The "entrypoint" node is an array of the names of all entrypoints added by the supported extension. | vkEnumerateDeviceExtensionProperties |
+| "enable\_environment" | **Implicit Layers Only** - **OPTIONAL:** Indicates an environment variable used to enable the Implicit Layer (w/ value of 1).  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).| N/A |
+| "disable\_environment" | **Implicit Layers Only** - **REQUIRED:**Indicates an environment variable used to disable the Implicit Layer (w/ value of 1). In rare cases of an application not working with an implicit layer, the application can set this environment variable (before calling Vulkan functions) in order to "blacklist" the layer. This environment variable (which 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. | N/A |
+
+
+##### Layer Manifest File Version History
+
+The current highest supported Layer Manifest file format supported is 1.1.0.
+Information about each version is detailed in the following sub-sections:
+
+###### Layer Manifest File Version 1.1.0
+
+Layer Manifest File Version 1.1.0 is tied to changes exposed by the Loader/Layer
+interface version 2.
+  1. Renaming "vkGetInstanceProcAddr" in the "functions" section is
+     deprecated since the loader no longer needs to query the layer about
+     "vkGetInstanceProcAddr" directly.  It is now returned during the layer
+     negotiation, so this field will be ignored.
+  2. Renaming "vkGetDeviceProcAddr" in the "functions" section is
+     deprecated since the loader no longer needs to query the layer about
+     "vkGetDeviceProcAddr" directly.  It too is now returned during the layer
+     negotiation, so this field will be ignored.
+  3. Renaming the "vkNegotiateLoaderLayerInterfaceVersion" function is
+     being added to the "functions" section, since this is now the only
+     function the loader needs to query using OS-specific calls.
+      - NOTE: This is an optional field and, as the two previous fields, only
+needed if the layer requires changing the name of the function for some reason.
+
+You do not need to update your layer manifest file if you don't change the
+names of any of the listed functions.
+
+###### Layer Manifest File Version 1.0.1
+
+The ability to define multiple layers using the "layers" array was added.  This
+JSON array field can be used when defining a single layer or multiple layers.
+The "layer" field is still present and valid for a single layer definition.
+
+###### Layer Manifest File Version 1.0.0
+
+The initial version of the layer manifest file specified the basic format and
+fields of a layer JSON file.  The fields of the 1.0.0 file format include:
+ * "file\_format\_version"
+ * "layer"
+ * "name"
+ * "type"
+ * "library\_path"
+ * "api\_version"
+ * "implementation\_version"
+ * "description"
+ * "functions"
+ * "instance\_extensions"
+ * "device\_extensions"
+ * "enable\_environment"
+ * "disable\_environment"
+
+It was also during this time that the value of "DEVICE" was deprecated from
+the "type" field.
+
+
+#### Layer Library Versions
+
+The current Layer Library interface is at version 2.  The following sections
+detail the differences between the various versions.
+
+##### Layer Library API Version 2
+
+Introduced the concept of
+[loader and layer interface](#layer-version-negotiation) using the new
+`vkNegotiateLoaderLayerInterfaceVersion` function. Additionally, it introduced
+the concept of
+[Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-
+extensions)
+and the associated `vk_layerGetPhysicalDeviceProcAddr` function.  Finally, it
+changed the manifest file defition to 1.1.0.
+
+##### Layer Library API Version 1
+
+A layer library supporting interface version 1 had the following behavior:
+ 1. `GetInstanceProcAddr` and `GetDeviceProcAddr` were directly exported
+ 2. The layer manifest file was able to override the names of the
+`GetInstanceProcAddr` and `GetDeviceProcAddr`functions.
+
+##### Layer Library API Version 0
+
+A layer library supporting interface version 0 must define and export these
+introspection functions, unrelated to any Vulkan function despite the names,
+signatures, and other similarities:
+
+ - `vkEnumerateInstanceLayerProperties` enumerates all layers in a layer
+library.
+  - This function never fails.
+  - When 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 function 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.
+
+It must also define and export these functions once for each layer in the
+library:
+
+ - `<layerName>GetInstanceProcAddr(instance, pName)` behaves identically to a
+layer's vkGetInstanceProcAddr except it is exported.
+
+   When 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 functions that they do not intercept.  They are recommended
+not to export any functions.
+
+
+<br/>
+<br/>
+
+## Vulkan Installable Client Driver Interface With the Loader
+
+This section discusses the various requirements for the loader and a Vulkan
+ICD to properly hand-shake.
+
+ * [ICD Discovery](#icd-discovery)
+  * [ICD Manifest File Usage](#icd-manifest-file-usage)
+  * [ICD Discovery on Windows](#icd-discovery-on-windows)
+  * [ICD Discovery on Linux](#icd-discovery-on-linux)
+  * [Using Pre-Production ICDs on Windows and Linux](#using-pre-production-icds-on-windows-and-linux)
+  * [ICD Discovery on Android](#icd-discovery-on-android)
+ * [ICD Manifest File Format](#icd-manifest-file-format)
+  * [ICD Manifest File Versions](#icd-manifest-file-versions)
+    * [ICD Manifest File Version 1.0.0](#icd-manifest-file-version-1.0.0)
+ * [ICD Vulkan Entry-Point Discovery](#icd-vulkan-entry-point-discovery)
+ * [ICD Unknown Physical Device Extensions](#icd-unknown-physical-device-extensions)
+ * [ICD Dispatchable Object Creation](#icd-dispatchable-object-creation)
+ * [Handling KHR Surface Objects in WSI Extensions](#handling-khr-surface-objects-in-wsi-extensions)
+ * [Loader and ICD Interface Negotiation](#loader-and-icd-interface-negotiation)
+  * [Windows and Linux ICD Negotiation](#windows-and-linux-icd-negotiation)
+    * [Version Negotiation Between Loader and ICDs](#version-negotiation-between-loader-and-icds)
+      * [Interfacing With Legacy ICDs or Loader](#interfacing-with-legacy-icds-or-loader]
+    * [Loader Version 4 Interface Requirements](#loader-version-4-interface-requirements)
+    * [Loader Version 3 Interface Requirements](#loader-version-3-interface-requirements)
+    * [Loader Version 2 Interface Requirements](#loader-version-2-interface-requirements)
+    * [Loader Versions 0 and 1 Interface Requirements](#loader-versions-0-and-1-interface-requirements)
+  * [Android ICD Negotiation](#android-icd-negotiation)
+
+
+### 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.
+
+#### ICD Manifest File Usage
+
+As with layers, on Windows and Linux systems, JSON formated manifest files are
+used to store ICD information.  In order to find system-installed drivers, the
+Vulkan loader will read the JSON files to identify the names and attributes of
+each driver.  One thing you will notice is that ICD Manifest files are much
+simpler than the corresponding layer Manifest files.
+
+See the [Current ICD Manifest File Format](#icd-manifest-file-format) section
+for more details.
+
+
+#### ICD Discovery on Windows
+
+In order to find installed ICDs, the Vulkan loader will scan the
+values in the following Windows registry key:
+
+```
+   HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers
+```
+
+For 32-bit applications on 64-bit Windows, the loader scan's the 32-bit
+registry location:
+
+```
+   HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\Vulkan\Drivers
+```
+
+The loader will look at the appropriate registry location and check each value
+listed.  If the key is of type DWORD, and it has a value of 0, the loader will
+open the JSON manifest file specified by the name.  Each name must be a full
+pathname to a text manifest file.  The Vulkan loader will attempt to open each
+manifest file to obtain the information about an ICD's shared library (".dll")
+file. 
+
+For example, let us assume the registry contains the following data:
+
+```
+[HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers\]
+
+"C:\vendor a\vk_vendora.json"=dword:00000000
+"C:\windows\system32\vendorb_vk.json"=dword:00000001
+"C:\windows\system32\vendorc_icd.json"=dword:00000000
+```
+
+In this case, the loader will step through each entry, and check the value.  If
+the value is 0, then the loader will attempt to load the file.  In this case,
+the loader will will open the first and last listings, but not the middle.  This
+is because the value of 1 for vendorb_vk.json disables the driver.
+
+The Vulkan loader will open each enabled manifest file found to obtain the name
+or pathname of an ICD shared library (".DLL") file.
+
+See the [ICD Manifest File Format](#icd-manifest-file-format) section for more
+details.
+
+
+#### ICD Discovery on Linux
+
+In order to find installed ICDs, the Vulkan loader will scan the files
+in the following Linux directories:
+
+```
+    /usr/local/etc/vulkan/icd.d
+    /usr/local/share/vulkan/icd.d
+    /etc/vulkan/icd.d
+    /usr/share/vulkan/icd.d
+    $HOME/.local/share/vulkan/icd.d
+```
+
+The "/usr/local/*" directories can be configured to be other directories at
+build time.
+
+The typical usage of the directories is indicated in the table below.
+
+| Location  |  Details |
+|-------------------|------------------------|
+| $HOME/.local/share/vulkan/icd.d | $HOME is the current home directory of the application's user id; this path will be ignored for suid programs |
+| "/usr/local/etc/vulkan/icd.d" | Directory for locally built ICDs |
+| "/usr/local/share/vulkan/icd.d" | Directory for locally built ICDs |
+| "/etc/vulkan/icd.d" | Location of ICDs installed from non-Linux-distribution-provided packages |
+| "/usr/share/vulkan/icd.d" | Location of ICDs installed from Linux-distribution-provided packages |
+
+The Vulkan loader will open each manifest file found to obtain the name or
+pathname of an ICD shared library (".so") file.
+
+See the [ICD Manifest File Format](#icd-manifest-file-format) section for more
+details.
+
+#### Using Pre-Production ICDs on Windows and Linux
+
+Independent Hardware Vendor (IHV) 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 system-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 system-installed ICDs. In
+other words, only the ICDs listed in "VK\_ICD\_FILENAMES" will be used.
+
+The "VK\_ICD\_FILENAMES" environment variable is a list of ICD
+manifest files, containing the full path to the ICD JSON Manifest file.  This
+list is colon-separated on Linux, and semi-colon separated on Windows.
+
+Typically, "VK\_ICD\_FILENAMES" will only contain a full pathname to one info
+file for a developer-built ICD. A separator (colon or semi-colon) is only used
+if more than one ICD is listed.
+
+**NOTE:** On Linux, this environment variable will be ignored for suid programs.
+
+
+#### ICD Discovery on 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.**
+
+
+### ICD Manifest File Format
+
+The following section discusses the details of the ICD Manifest JSON file
+format.  The JSON file itself does not have any requirements for naming.  The
+only requirement is that the extension suffix of the file ends with ".json".
+
+Here is an example layer JSON Manifest file:
+
+```
+{
+   "file_format_version": "1.0.0",
+   "ICD": {
+      "library_path": "path to ICD library",
+      "api_version": "1.0.5"
+   }
+}
+```
+
+| Field Name | Field Value |
+|----------------|--------------------|
+| "file\_format\_version" | The JSON format major.minor.patch version number of this file.  Currently supported version is 1.0.0. |
+| "ICD" | The identifier used to group all ICD information together. |
+| "library_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file.  If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file.  If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the ICD shared library files other than it should end with the appropriate suffix (".DLL" on Windows, and ".so" on Linux). | N/A |
+| "api_version" | The major.minor.patch version number of the Vulkan API that the shared library files for the ICD was built against. For example: 1.0.33. |
+
+**NOTE:** 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).
+
+##### ICD Manifest File Versions
+
+There has only been one version of the ICD manifest files supported.  This is
+version 1.0.0.
+
+###### ICD Manifest File Version 1.0.0
+
+The initial version of the ICD Manifest file specified the basic format and
+fields of a layer JSON file.  The fields of the 1.0.0 file format include:
+ * "file\_format\_version"
+ * "ICD"
+ * "library\_path"
+ * "api\_version"
+
+ 
+###  ICD Vulkan Entry-Point Discovery
+
+The Vulkan symbols exported by an ICD must not clash with the loader's exported
+Vulkan symbols.  This could be for several reasons.  Because of this, 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.
+
+```cpp
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(
+                                               VkInstance instance,
+                                               const char* pName);
+```
+
+This function has very similar semantics to `vkGetInstanceProcAddr`.
+`vk_icdGetInstanceProcAddr` returns valid function pointers for all the global-
+level and instance-level Vulkan functions, and also for `vkGetDeviceProcAddr`.
+Global-level functions 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 functions 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 directly from the ICD library
+ * or NOT use the official Vulkan function names if they are exported
+ 
+This requirement is for ICD libraries that include other
+functionality (such as OpenGL) and thus could be loaded by the
+application prior to when the Vulkan loader library is loaded by the
+application.
+
+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.
+
+
+### ICD Unknown Physical Device Extensions
+
+Originally, if the loader was called with `vkGetInstanceProcAddr`, it would
+result in the following behavior:
+ 1. The loader would check if core function:
+    - If it was, it would return the function pointer
+ 2. The loader would check if known extension function:
+    - If it was, it would return the function pointer
+ 3. If the loader knew nothing about it, it would call down using
+`GetInstanceProcAddr`
+    - If it returned non-NULL, treat it as an unknown logical device command.
+    - This meant setting up a generic trampoline function that takes in a
+VkDevice as the first parameter and adjusting the dispatch table to call the
+ICD/Layers function after getting the dispatch table from the VkDevice.
+ 4. If all the above failed, the loader would return NULL to the application.
+
+This caused problems when an ICD attempted to expose new physical device
+extensions the loader knew nothing about, but an application did.  Because the
+loader knew nothing about it, the loader would get to step 3 in the above
+process and would treat the function as an unknown logical device command.  The
+problem is, this would create a generic VkDevice trampoline function which, on
+the first call, would attempt to dereference the VkPhysicalDevice as a VkDevice.
+This would lead to a crash or corruption.
+
+In order to identify the extension entry-points specific to physical device
+extensions, the following function can be added to an ICD:
+
+```cpp
+PFN_vkVoidFunction vk_icdGetPhysicalDeviceProcAddr(VkInstance instance,
+                                                   const char* pName);
+```
+
+This function behaves similar to `vkGetInstanceProcAddr` and
+`vkGetDeviceProcAddr` except it should only return values for physical device
+extension entry-points.  In this way, it compares "pName" to every physical
+device function supported in the ICD.
+
+The following rules apply:
+ * If it is the name of a physical device function supported by the ICD, the
+pointer to the ICD's corresponding function should be returned.
+ * If it is the name of a valid function which is **not** a physical device
+function (i.e. an Instance, Device, or other function implemented by the ICD),
+then the value of NULL should be returned.
+ * If the ICD has no idea what this function is, it should return NULL.
+
+This support is optional and should not be considered a requirement.  This is
+only required if an ICD intends to support some functionality not directly
+supported by a significant population of loaders in the public.  If an ICD
+does implent this support, it should return the address of its
+`vk_icdGetPhysicalDeviceProcAddr` function through the `vkGetInstanceProcAddr`
+function.
+
+The new behavior of the loader's vkGetInstanceProcAddr with support for the
+`vk_icdGetPhysicalDeviceProcAddr` function is as follows:
+ 1. Check if core function:
+    - If it is, return the function pointer
+ 2. Check if known instance or device extension function:
+    - If it is, return the function pointer
+ 3. Call the layer/ICD `GetPhysicalDeviceProcAddr`
+    - If it returns non-NULL, return a trampoline to a generic physical device
+function, and setup a generic terminator which will pass it to the proper ICD.
+ 4. Call down using `GetInstanceProcAddr`
+    - If it returns non-NULL, treat it as an unknown logical device command.
+This means setting up a generic trampoline function that takes in a VkDevice as
+the first parameter and adjusting the dispatch table to call the ICD/Layers
+function after getting the dispatch table from the VkDevice. Then, return the
+pointer to corresponding trampoline function.
+ 5. Return NULL
+
+You can see now, that, if the command gets promoted to core later, it will no
+longer be setup using `vk_icdGetPhysicalDeviceProcAddr`.  Additionally, if the
+loader adds direct support for the extension, it will no longer get to step 3,
+because step 2 will return a valid function pointer.  However, the ICD should
+continue to support the command query via `vk_icdGetPhysicalDeviceProcAddr`,
+until at least a Vulkan version bump, because an older loader may still be
+attempting to use the commands.
+
+
+### ICD Dispatchable Object Creation
+
+As previously covered, the loader requires dispatch tables to be accessible
+within Vulkan dispatchable objects, such as: `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`):
+
+```cpp
+#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;
+}
+```
+ 
+
+### Handling KHR Surface Objects in 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 may be handled by either the loader, or an ICD.
+
+If the loader handles the management of the `VkSurfaceKHR` objects:
+ 1. The loader will handle the calls to `vkCreateXXXSurfaceKHR` and
+`vkDestroySurfaceKHR`
+    functions without involving the ICDs.
+    * Where XXX stands for the Windowing System name:
+      * Mir
+      * Wayland
+      * Xcb
+      * Xlib
+      * Windows
+      * Android
+ 2. The loader creates a `VkIcdSurfaceXXX` object for the corresponding
+`vkCreateXXXSurfaceKHR` call.
+    * The `VkIcdSurfaceXXX` structures are defined in `include/vulkan/vk_icd.h`.
+ 3. ICDs can cast any `VkSurfaceKHR` object to a pointer to the appropriate
+    `VkIcdSurfaceXXX` structure.
+ 4. The first field of all the `VkIcdSurfaceXXX` structures is a
+`VkIcdSurfaceBase` enumerant that indicates whether the
+    surface object is Win32, Xcb, Xlib, Mir, or Wayland.
+
+The ICD may choose to handle `VkSurfaceKHR` object creation instead.  If an ICD
+desires to handle creating and destroying it must do the following:
+ 1. Support version 3 or newer of the loader/ICD interface.
+ 2. Export and handle all functions that take in a `VkSurfaceKHR` object,
+including:
+     * `vkCreateXXXSurfaceKHR`
+     * `vkGetPhysicalDeviceSurfaceSupportKHR`
+     * `vkGetPhysicalDeviceSurfaceCapabilitiesKHR`
+     * `vkGetPhysicalDeviceSurfaceFormatsKHR`
+     * `vkGetPhysicalDeviceSurfacePresentModesKHR`
+     * `vkCreateSwapchainKHR`
+     * `vkDestroySurfaceKHR`
+
+Because the `VkSurfaceKHR` object is an instance-level object, one object can be
+associated with multiple ICDs.  Therefore, when the loader receives the
+`vkCreateXXXSurfaceKHR` call, it still creates an internal `VkSurfaceIcdXXX`
+object.  This object acts as a container for each ICD's version of the
+`VkSurfaceKHR` object.  If an ICD does not support the creation of its own
+`VkSurfaceKHR` object, the loader's container stores a NULL for that ICD.  On
+the otherhand, if the ICD does support `VkSurfaceKHR` creation, the loader will
+make the appropriate `vkCreateXXXSurfaceKHR` call to the ICD, and store the
+returned pointer in it's container object.  The loader then returns the
+`VkSurfaceIcdXXX` as a `VkSurfaceKHR` object back up the call chain.  Finally,
+when the loader receives the `vkDestroySurfaceKHR` call, it subsequently calls
+`vkDestroySurfaceKHR` for each ICD who's internal `VkSurfaceKHR` object is not
+NULL.  Then the loader destroys the container object before returning.
+
+
+### Loader and ICD Interface Negotiation
+
+Generally, for functions issued by an application, the loader can be
+viewed as a pass through. That is, the loader generally doesn't modify the
+functions or their parameters, but simply calls the ICDs entry-point for that
+function. There are specific additional interface requirements an ICD needs to
+comply with that are not part of any requirements from the Vulkan specification.
+These addtional requirements are versioned to allow flexibility in the future.
+
+
+#### Windows and Linux ICD Negotiation
+
+
+##### 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.
+
+```cpp
+   VKAPI_ATTR VkResult VKAPI_CALL
+       vk_icdNegotiateLoaderICDInterfaceVersion(
+           uint32_t* pSupportedVersion);
+```
+
+This function allows the loader and ICD to agree on an interface version to use.
+The "pSupportedVersion" parameter is both an input and output parameter.
+"pSupportedVersion" is filled in by the loader with the desired latest interface
+version supported by the loader (typically the latest). The ICD receives this
+and returns back the version it desires in the same field.  Because it is
+setting up the interface version between the loader and ICD, this should be
+the first call made by a loader to the ICD (even prior to any calls to
+`vk_icdGetInstanceProcAddr`).
+
+If the ICD receiving the call no longer supports the interface version provided
+by the loader (due to deprecation), then it should 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 its 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 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.
+
+###### Interfacing With Legacy ICDs or Loader
+
+If a loader sees that an ICD does not export the
+`vk_icdNegotiateLoaderICDInterfaceVersion` function, then the loader assumes the
+corresponding ICD only supports either interface version 0 or 1.
+
+From the other side of the interface, if an ICD sees a call to
+`vk_icdGetInstanceProcAddr` before a call to
+`vk_icdGetLoaderICDInterfaceVersion`, then it knows that loader making the calls
+is a legacy loader supporting version 0 or 1.  If the loader calls
+`vk_icdGetInstanceProcAddr` first, it supports at least version 1.  Otherwise,
+the loader only supports version 0.
+
+
+##### Loader Version 4 Interface Requirements
+
+The major change to version 4 of the loader/ICD interface is the support of
+[Unknown Physical Device Extensions](#icd-unknown-physical-device-
+extensions] using the `vk_icdGetPhysicalDeviceProcAddr` function.  This
+function is purely optional.  However, if an ICD supports a Physical Device
+extension, it must provide a `vk_icdGetPhysicalDeviceProcAddr` function.
+Otherwise, the loader will continue to treat any unknown functions as VkDevice
+functions and cause invalid behavior.
+
+
+##### Loader Version 3 Interface Requirements
+
+The primary change that occurred in version 3 of the loader/ICD interface was 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, it must export support for version 3 of the
+loader/ICD interface, as well as any Vulkan function that uses a KHR_surface
+handle, such as:
+- `vkCreateXXXSurfaceKHR` (where XXX is the platform specific identifier [i.e.
+`vkCreateWin32SurfaceKHR` 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`
+functions.
+
+
+##### 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.
+
+##### Loader Versions 0 and 1 Interface Requirements
+
+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:
+
+- The function `vkGetInstanceProcAddr` **must be exported** in the ICD library
+and returns valid function pointers for all the Vulkan API entry-points.
+- `vkCreateInstance` **must be exported** by the ICD library.
+- `vkEnumerateInstanceExtensionProperties` **must be exported** by 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 author 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` if "pLayerName" is not equal to `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
+[Creating New Dispatchable Objects](#creating-new-dispatchable-objects) section
+for more information on how to initialize created dispatchable objects for
+extensions non known by the loader.
+
+
+#### Android ICD Negotiation
+
+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.
+
+ 
+## Glossary of Terms
+
+| Field Name | Field Value |
+|----------------|--------------------|
+| Android Loader | The loader designed to work primarily for the Android OS.  This is generated from a different code-base than the desktop loader.  But, in all important aspects, should be functionally equivalent. |
+| Desktop Loader | The loader designed to work on both Windows and Linux.  This is generated from a different [code-base](#https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers) than the Android loader.  But in all important aspects, should be functionally equivalent. |
+| Core Function | A function that is already part of the Vulkan core specification and not an extension.  For example, vkCreateDevice(). |
+| Device Call Chain | The call chain of functions followed for device functions.  This call chain for a device function is usually as follows: first the application calls into a loader trampoline, then the loader trampoline calls enabled layers, the final layer calls into the ICD specific to the device.  See the [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) section for more information |
+| Device Function | A Device function is any Vulkan function which takes a `VkDevice`, `VkQueue`, `VkCommandBuffer`, or any child of these, as its first parameter.  Some Vulkan Device functions are: `vkQueueSubmit`, `vkBeginCommandBuffer`, `vkCreateEvent`.  See the [Instance Versus Device](#instance-versus-device) section for more information. |
+| Discovery | The process of the loader searching for ICD and Layer files to setup the internal list of Vulkan objects available.  On Windows/Linux, the discovery process typically focuses on searching for Manifest files.  While on Android, the process focuses on searching for library files. |
+| Dispatch Table | An array of function pointers (including core and possibly extension functions) used to step to the next entity in a call chain.  The entity could be the loader, a layer or an ICD.  See [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) for more information.  |
+| Extension | A concept of Vulkan used to expand the core Vulkan functionality.  Extensions may be IHV-specific, platform-specific, or more broadly available.  You should always query if an extension exists, and enable it during `vkCreateInstance` (if it is an instance extension) or during `vkCreateDevice` (if it is a device extension). |
+| ICD | Acronym for Installable Client Driver.  These are drivers that are provided by IHVs to interact with the hardware they provide.  See [Installable Client Drivers](#installable-client-drivers) section for more information.
+| IHV | Acronym for an Independent Hardware Vendor.  Typically the company that built the underlying hardware technology you are trying to use.  A typical examples for a Graphics IHV are: AMD, ARM, Imagination, Intel, Nvidia, Qualcomm, etc. |
+| Instance Call Chain | The call chain of functions followed for instance functions.  This call chain for an instance function is usually as follows: first the application calls into a loader trampoline, then the loader trampoline calls enabled layers, the final layer calls a loader terminator, and the loader terminator calls all available ICDs.  See the [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) section for more information |
+| Instance Function | An Instance function is any Vulkan function which takes as its first parameter either a `VkInstance` or a `VkPhysicalDevice` or nothing at all.  Some Vulkan Instance functions are: `vkEnumerateInstanceExtensionProperties`, `vkEnumeratePhysicalDevices`, `vkCreateInstance`, `vkDestroyInstance`.  See the [Instance Versus Device](#instance-versus-device) section for more information. |
+| Layer | Layers are optional components that augment the Vulkan system.  They can intercept, evaluate, and modify existing Vulkan functions on their way from the application down to the hardware.  See the [Layers](#layers) section for more information. |
+| Loader | The middle-ware program which acts as the mediator between Vulkan applications, Vulkan layers and Vulkan drivers.  See [The Loader](#the loader) section for more information. |
+| Manifest Files | Data files in JSON format used by the desktop loader.  These files contain specific information for either a [Layer](#layer-manifest-file-format) or an [ICD](#icd-manifest-file-format).
+| Terminator Function | The last function in the instance call chain above the ICDs and owned by the loader.  This function is required in the instance call chain because all instance functionality must be communicated to all ICDs capable of receiving the call.  See [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) for more information. |
+| Trampoline Function | The first function in an instance or device call chain owned by the loader which handles the setup and proper call chain walk using the appropriate dispatch table.  On device functions (in the device call chain) this function can actually be skipped.  See [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) for more information. |
+| WSI Extension | Acronym for Windowing System Integration.  A Vulkan extension targeting a particular Windowing and designed to interface between the Windowing system and Vulkan. See [WSI Extensions](#wsi-extensions) for more information. |
diff --git a/loader/chain_skipping_layers.png b/loader/chain_skipping_layers.png
deleted file mode 100644
index 0eca54e..0000000
--- a/loader/chain_skipping_layers.png
+++ /dev/null
Binary files differ
diff --git a/loader/debug_report.c b/loader/debug_report.c
index 15233bc..bf9ff41 100644
--- a/loader/debug_report.c
+++ b/loader/debug_report.c
@@ -103,7 +103,7 @@
     VkDebugReportCallbackEXT *pCallback) {
     struct loader_instance *inst = loader_get_instance(instance);
     loader_platform_thread_lock_mutex(&loader_lock);
-    VkResult result = inst->disp->CreateDebugReportCallbackEXT(
+    VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(
         instance, pCreateInfo, pAllocator, pCallback);
     loader_platform_thread_unlock_mutex(&loader_lock);
     return result;
@@ -295,7 +295,8 @@
     struct loader_instance *inst = loader_get_instance(instance);
     loader_platform_thread_lock_mutex(&loader_lock);
 
-    inst->disp->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(
+        instance, callback, pAllocator);
 
     util_DestroyDebugReportCallback(inst, callback, pAllocator);
 
@@ -308,8 +309,9 @@
     int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
     struct loader_instance *inst = loader_get_instance(instance);
 
-    inst->disp->DebugReportMessageEXT(instance, flags, objType, object,
-                                      location, msgCode, pLayerPrefix, pMsg);
+    inst->disp->layer_inst_disp.DebugReportMessageEXT(
+        instance, flags, objType, object, location, msgCode, pLayerPrefix,
+        pMsg);
 }
 
 /*
diff --git a/loader/dev_ext_trampoline.c b/loader/dev_ext_trampoline.c
index e1cf625..e1ffa37 100644
--- a/loader/dev_ext_trampoline.c
+++ b/loader/dev_ext_trampoline.c
@@ -24,2008 +24,519 @@
 #pragma GCC optimize(3) // force gcc to use tail-calls
 #endif
 
-VKAPI_ATTR void VKAPI_CALL vkdev_ext0(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[0](device);
-}
+ // Trampoline function macro for unknown physical device extension command.
+#define DevExtTramp(num)                                                       \
+VKAPI_ATTR void VKAPI_CALL vkdev_ext##num(VkDevice device) {                   \
+        const struct loader_dev_dispatch_table *disp;                          \
+        disp = loader_get_dev_dispatch(device);                                \
+        disp->ext_dispatch.dev_ext[num](device);                               \
+    }
 
-VKAPI_ATTR void VKAPI_CALL vkdev_ext1(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[1](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext2(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[2](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext3(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[3](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext4(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[4](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext5(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[5](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext6(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[6](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext7(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[7](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext8(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[8](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext9(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[9](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext10(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[10](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext11(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[11](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext12(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[12](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext13(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[13](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext14(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[14](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext15(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[15](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext16(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[16](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext17(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[17](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext18(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[18](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext19(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[19](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext20(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[20](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext21(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[21](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext22(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[22](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext23(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[23](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext24(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[24](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext25(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[25](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext26(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[26](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext27(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[27](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext28(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[28](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext29(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[29](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext30(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[30](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext31(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[31](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext32(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[32](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext33(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[33](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext34(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[34](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext35(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[35](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext36(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[36](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext37(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[37](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext38(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[38](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext39(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[39](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext40(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[40](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext41(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[41](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext42(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[42](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext43(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[43](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext44(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[44](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext45(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[45](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext46(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[46](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext47(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[47](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext48(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[48](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext49(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[49](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext50(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[50](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext51(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[51](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext52(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[52](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext53(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[53](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext54(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[54](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext55(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[55](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext56(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[56](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext57(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[57](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext58(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[58](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext59(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[59](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext60(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[60](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext61(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[61](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext62(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[62](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext63(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[63](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext64(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[64](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext65(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[65](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext66(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[66](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext67(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[67](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext68(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[68](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext69(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[69](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext70(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[70](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext71(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[71](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext72(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[72](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext73(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[73](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext74(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[74](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext75(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[75](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext76(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[76](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext77(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[77](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext78(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[78](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext79(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[79](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext80(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[80](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext81(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[81](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext82(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[82](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext83(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[83](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext84(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[84](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext85(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[85](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext86(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[86](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext87(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[87](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext88(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[88](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext89(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[89](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext90(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[90](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext91(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[91](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext92(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[92](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext93(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[93](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext94(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[94](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext95(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[95](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext96(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[96](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext97(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[97](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext98(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[98](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext99(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[99](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext100(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[100](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext101(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[101](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext102(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[102](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext103(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[103](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext104(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[104](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext105(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[105](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext106(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[106](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext107(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[107](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext108(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[108](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext109(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[109](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext110(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[110](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext111(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[111](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext112(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[112](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext113(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[113](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext114(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[114](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext115(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[115](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext116(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[116](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext117(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[117](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext118(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[118](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext119(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[119](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext120(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[120](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext121(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[121](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext122(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[122](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext123(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[123](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext124(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[124](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext125(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[125](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext126(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[126](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext127(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[127](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext128(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[128](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext129(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[129](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext130(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[130](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext131(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[131](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext132(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[132](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext133(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[133](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext134(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[134](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext135(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[135](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext136(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[136](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext137(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[137](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext138(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[138](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext139(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[139](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext140(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[140](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext141(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[141](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext142(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[142](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext143(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[143](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext144(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[144](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext145(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[145](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext146(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[146](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext147(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[147](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext148(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[148](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext149(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[149](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext150(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[150](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext151(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[151](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext152(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[152](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext153(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[153](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext154(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[154](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext155(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[155](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext156(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[156](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext157(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[157](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext158(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[158](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext159(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[159](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext160(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[160](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext161(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[161](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext162(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[162](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext163(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[163](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext164(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[164](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext165(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[165](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext166(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[166](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext167(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[167](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext168(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[168](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext169(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[169](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext170(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[170](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext171(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[171](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext172(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[172](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext173(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[173](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext174(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[174](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext175(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[175](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext176(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[176](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext177(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[177](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext178(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[178](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext179(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[179](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext180(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[180](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext181(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[181](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext182(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[182](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext183(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[183](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext184(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[184](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext185(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[185](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext186(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[186](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext187(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[187](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext188(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[188](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext189(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[189](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext190(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[190](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext191(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[191](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext192(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[192](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext193(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[193](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext194(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[194](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext195(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[195](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext196(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[196](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext197(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[197](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext198(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[198](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext199(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[199](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext200(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[200](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext201(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[201](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext202(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[202](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext203(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[203](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext204(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[204](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext205(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[205](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext206(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[206](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext207(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[207](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext208(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[208](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext209(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[209](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext210(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[210](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext211(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[211](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext212(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[212](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext213(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[213](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext214(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[214](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext215(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[215](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext216(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[216](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext217(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[217](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext218(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[218](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext219(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[219](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext220(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[220](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext221(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[221](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext222(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[222](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext223(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[223](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext224(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[224](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext225(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[225](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext226(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[226](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext227(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[227](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext228(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[228](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext229(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[229](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext230(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[230](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext231(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[231](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext232(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[232](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext233(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[233](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext234(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[234](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext235(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[235](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext236(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[236](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext237(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[237](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext238(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[238](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext239(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[239](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext240(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[240](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext241(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[241](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext242(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[242](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext243(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[243](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext244(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[244](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext245(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[245](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext246(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[246](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext247(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[247](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext248(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[248](device);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkdev_ext249(VkDevice device) {
-    const struct loader_dev_dispatch_table *disp;
-    disp = loader_get_dev_dispatch(device);
-    disp->ext_dispatch.dev_ext[249](device);
-}
+DevExtTramp(0)
+DevExtTramp(1)
+DevExtTramp(2)
+DevExtTramp(3)
+DevExtTramp(4)
+DevExtTramp(5)
+DevExtTramp(6)
+DevExtTramp(7)
+DevExtTramp(8)
+DevExtTramp(9)
+DevExtTramp(10)
+DevExtTramp(11)
+DevExtTramp(12)
+DevExtTramp(13)
+DevExtTramp(14)
+DevExtTramp(15)
+DevExtTramp(16)
+DevExtTramp(17)
+DevExtTramp(18)
+DevExtTramp(19)
+DevExtTramp(20)
+DevExtTramp(21)
+DevExtTramp(22)
+DevExtTramp(23)
+DevExtTramp(24)
+DevExtTramp(25)
+DevExtTramp(26)
+DevExtTramp(27)
+DevExtTramp(28)
+DevExtTramp(29)
+DevExtTramp(30)
+DevExtTramp(31)
+DevExtTramp(32)
+DevExtTramp(33)
+DevExtTramp(34)
+DevExtTramp(35)
+DevExtTramp(36)
+DevExtTramp(37)
+DevExtTramp(38)
+DevExtTramp(39)
+DevExtTramp(40)
+DevExtTramp(41)
+DevExtTramp(42)
+DevExtTramp(43)
+DevExtTramp(44)
+DevExtTramp(45)
+DevExtTramp(46)
+DevExtTramp(47)
+DevExtTramp(48)
+DevExtTramp(49)
+DevExtTramp(50)
+DevExtTramp(51)
+DevExtTramp(52)
+DevExtTramp(53)
+DevExtTramp(54)
+DevExtTramp(55)
+DevExtTramp(56)
+DevExtTramp(57)
+DevExtTramp(58)
+DevExtTramp(59)
+DevExtTramp(60)
+DevExtTramp(61)
+DevExtTramp(62)
+DevExtTramp(63)
+DevExtTramp(64)
+DevExtTramp(65)
+DevExtTramp(66)
+DevExtTramp(67)
+DevExtTramp(68)
+DevExtTramp(69)
+DevExtTramp(70)
+DevExtTramp(71)
+DevExtTramp(72)
+DevExtTramp(73)
+DevExtTramp(74)
+DevExtTramp(75)
+DevExtTramp(76)
+DevExtTramp(77)
+DevExtTramp(78)
+DevExtTramp(79)
+DevExtTramp(80)
+DevExtTramp(81)
+DevExtTramp(82)
+DevExtTramp(83)
+DevExtTramp(84)
+DevExtTramp(85)
+DevExtTramp(86)
+DevExtTramp(87)
+DevExtTramp(88)
+DevExtTramp(89)
+DevExtTramp(90)
+DevExtTramp(91)
+DevExtTramp(92)
+DevExtTramp(93)
+DevExtTramp(94)
+DevExtTramp(95)
+DevExtTramp(96)
+DevExtTramp(97)
+DevExtTramp(98)
+DevExtTramp(99)
+DevExtTramp(100)
+DevExtTramp(101)
+DevExtTramp(102)
+DevExtTramp(103)
+DevExtTramp(104)
+DevExtTramp(105)
+DevExtTramp(106)
+DevExtTramp(107)
+DevExtTramp(108)
+DevExtTramp(109)
+DevExtTramp(110)
+DevExtTramp(111)
+DevExtTramp(112)
+DevExtTramp(113)
+DevExtTramp(114)
+DevExtTramp(115)
+DevExtTramp(116)
+DevExtTramp(117)
+DevExtTramp(118)
+DevExtTramp(119)
+DevExtTramp(120)
+DevExtTramp(121)
+DevExtTramp(122)
+DevExtTramp(123)
+DevExtTramp(124)
+DevExtTramp(125)
+DevExtTramp(126)
+DevExtTramp(127)
+DevExtTramp(128)
+DevExtTramp(129)
+DevExtTramp(130)
+DevExtTramp(131)
+DevExtTramp(132)
+DevExtTramp(133)
+DevExtTramp(134)
+DevExtTramp(135)
+DevExtTramp(136)
+DevExtTramp(137)
+DevExtTramp(138)
+DevExtTramp(139)
+DevExtTramp(140)
+DevExtTramp(141)
+DevExtTramp(142)
+DevExtTramp(143)
+DevExtTramp(144)
+DevExtTramp(145)
+DevExtTramp(146)
+DevExtTramp(147)
+DevExtTramp(148)
+DevExtTramp(149)
+DevExtTramp(150)
+DevExtTramp(151)
+DevExtTramp(152)
+DevExtTramp(153)
+DevExtTramp(154)
+DevExtTramp(155)
+DevExtTramp(156)
+DevExtTramp(157)
+DevExtTramp(158)
+DevExtTramp(159)
+DevExtTramp(160)
+DevExtTramp(161)
+DevExtTramp(162)
+DevExtTramp(163)
+DevExtTramp(164)
+DevExtTramp(165)
+DevExtTramp(166)
+DevExtTramp(167)
+DevExtTramp(168)
+DevExtTramp(169)
+DevExtTramp(170)
+DevExtTramp(171)
+DevExtTramp(172)
+DevExtTramp(173)
+DevExtTramp(174)
+DevExtTramp(175)
+DevExtTramp(176)
+DevExtTramp(177)
+DevExtTramp(178)
+DevExtTramp(179)
+DevExtTramp(180)
+DevExtTramp(181)
+DevExtTramp(182)
+DevExtTramp(183)
+DevExtTramp(184)
+DevExtTramp(185)
+DevExtTramp(186)
+DevExtTramp(187)
+DevExtTramp(188)
+DevExtTramp(189)
+DevExtTramp(190)
+DevExtTramp(191)
+DevExtTramp(192)
+DevExtTramp(193)
+DevExtTramp(194)
+DevExtTramp(195)
+DevExtTramp(196)
+DevExtTramp(197)
+DevExtTramp(198)
+DevExtTramp(199)
+DevExtTramp(200)
+DevExtTramp(201)
+DevExtTramp(202)
+DevExtTramp(203)
+DevExtTramp(204)
+DevExtTramp(205)
+DevExtTramp(206)
+DevExtTramp(207)
+DevExtTramp(208)
+DevExtTramp(209)
+DevExtTramp(210)
+DevExtTramp(211)
+DevExtTramp(212)
+DevExtTramp(213)
+DevExtTramp(214)
+DevExtTramp(215)
+DevExtTramp(216)
+DevExtTramp(217)
+DevExtTramp(218)
+DevExtTramp(219)
+DevExtTramp(220)
+DevExtTramp(221)
+DevExtTramp(222)
+DevExtTramp(223)
+DevExtTramp(224)
+DevExtTramp(225)
+DevExtTramp(226)
+DevExtTramp(227)
+DevExtTramp(228)
+DevExtTramp(229)
+DevExtTramp(230)
+DevExtTramp(231)
+DevExtTramp(232)
+DevExtTramp(233)
+DevExtTramp(234)
+DevExtTramp(235)
+DevExtTramp(236)
+DevExtTramp(237)
+DevExtTramp(238)
+DevExtTramp(239)
+DevExtTramp(240)
+DevExtTramp(241)
+DevExtTramp(242)
+DevExtTramp(243)
+DevExtTramp(244)
+DevExtTramp(245)
+DevExtTramp(246)
+DevExtTramp(247)
+DevExtTramp(248)
+DevExtTramp(249)
 
 void *loader_get_dev_ext_trampoline(uint32_t index) {
     switch (index) {
-    case 0:
-        return vkdev_ext0;
-    case 1:
-        return vkdev_ext1;
-    case 2:
-        return vkdev_ext2;
-    case 3:
-        return vkdev_ext3;
-    case 4:
-        return vkdev_ext4;
-    case 5:
-        return vkdev_ext5;
-    case 6:
-        return vkdev_ext6;
-    case 7:
-        return vkdev_ext7;
-    case 8:
-        return vkdev_ext8;
-    case 9:
-        return vkdev_ext9;
-    case 10:
-        return vkdev_ext10;
-    case 11:
-        return vkdev_ext11;
-    case 12:
-        return vkdev_ext12;
-    case 13:
-        return vkdev_ext13;
-    case 14:
-        return vkdev_ext14;
-    case 15:
-        return vkdev_ext15;
-    case 16:
-        return vkdev_ext16;
-    case 17:
-        return vkdev_ext17;
-    case 18:
-        return vkdev_ext18;
-    case 19:
-        return vkdev_ext19;
-    case 20:
-        return vkdev_ext20;
-    case 21:
-        return vkdev_ext21;
-    case 22:
-        return vkdev_ext22;
-    case 23:
-        return vkdev_ext23;
-    case 24:
-        return vkdev_ext24;
-    case 25:
-        return vkdev_ext25;
-    case 26:
-        return vkdev_ext26;
-    case 27:
-        return vkdev_ext27;
-    case 28:
-        return vkdev_ext28;
-    case 29:
-        return vkdev_ext29;
-    case 30:
-        return vkdev_ext30;
-    case 31:
-        return vkdev_ext31;
-    case 32:
-        return vkdev_ext32;
-    case 33:
-        return vkdev_ext33;
-    case 34:
-        return vkdev_ext34;
-    case 35:
-        return vkdev_ext35;
-    case 36:
-        return vkdev_ext36;
-    case 37:
-        return vkdev_ext37;
-    case 38:
-        return vkdev_ext38;
-    case 39:
-        return vkdev_ext39;
-    case 40:
-        return vkdev_ext40;
-    case 41:
-        return vkdev_ext41;
-    case 42:
-        return vkdev_ext42;
-    case 43:
-        return vkdev_ext43;
-    case 44:
-        return vkdev_ext44;
-    case 45:
-        return vkdev_ext45;
-    case 46:
-        return vkdev_ext46;
-    case 47:
-        return vkdev_ext47;
-    case 48:
-        return vkdev_ext48;
-    case 49:
-        return vkdev_ext49;
-    case 50:
-        return vkdev_ext50;
-    case 51:
-        return vkdev_ext51;
-    case 52:
-        return vkdev_ext52;
-    case 53:
-        return vkdev_ext53;
-    case 54:
-        return vkdev_ext54;
-    case 55:
-        return vkdev_ext55;
-    case 56:
-        return vkdev_ext56;
-    case 57:
-        return vkdev_ext57;
-    case 58:
-        return vkdev_ext58;
-    case 59:
-        return vkdev_ext59;
-    case 60:
-        return vkdev_ext60;
-    case 61:
-        return vkdev_ext61;
-    case 62:
-        return vkdev_ext62;
-    case 63:
-        return vkdev_ext63;
-    case 64:
-        return vkdev_ext64;
-    case 65:
-        return vkdev_ext65;
-    case 66:
-        return vkdev_ext66;
-    case 67:
-        return vkdev_ext67;
-    case 68:
-        return vkdev_ext68;
-    case 69:
-        return vkdev_ext69;
-    case 70:
-        return vkdev_ext70;
-    case 71:
-        return vkdev_ext71;
-    case 72:
-        return vkdev_ext72;
-    case 73:
-        return vkdev_ext73;
-    case 74:
-        return vkdev_ext74;
-    case 75:
-        return vkdev_ext75;
-    case 76:
-        return vkdev_ext76;
-    case 77:
-        return vkdev_ext77;
-    case 78:
-        return vkdev_ext78;
-    case 79:
-        return vkdev_ext79;
-    case 80:
-        return vkdev_ext80;
-    case 81:
-        return vkdev_ext81;
-    case 82:
-        return vkdev_ext82;
-    case 83:
-        return vkdev_ext83;
-    case 84:
-        return vkdev_ext84;
-    case 85:
-        return vkdev_ext85;
-    case 86:
-        return vkdev_ext86;
-    case 87:
-        return vkdev_ext87;
-    case 88:
-        return vkdev_ext88;
-    case 89:
-        return vkdev_ext89;
-    case 90:
-        return vkdev_ext90;
-    case 91:
-        return vkdev_ext91;
-    case 92:
-        return vkdev_ext92;
-    case 93:
-        return vkdev_ext93;
-    case 94:
-        return vkdev_ext94;
-    case 95:
-        return vkdev_ext95;
-    case 96:
-        return vkdev_ext96;
-    case 97:
-        return vkdev_ext97;
-    case 98:
-        return vkdev_ext98;
-    case 99:
-        return vkdev_ext99;
-    case 100:
-        return vkdev_ext100;
-    case 101:
-        return vkdev_ext101;
-    case 102:
-        return vkdev_ext102;
-    case 103:
-        return vkdev_ext103;
-    case 104:
-        return vkdev_ext104;
-    case 105:
-        return vkdev_ext105;
-    case 106:
-        return vkdev_ext106;
-    case 107:
-        return vkdev_ext107;
-    case 108:
-        return vkdev_ext108;
-    case 109:
-        return vkdev_ext109;
-    case 110:
-        return vkdev_ext110;
-    case 111:
-        return vkdev_ext111;
-    case 112:
-        return vkdev_ext112;
-    case 113:
-        return vkdev_ext113;
-    case 114:
-        return vkdev_ext114;
-    case 115:
-        return vkdev_ext115;
-    case 116:
-        return vkdev_ext116;
-    case 117:
-        return vkdev_ext117;
-    case 118:
-        return vkdev_ext118;
-    case 119:
-        return vkdev_ext119;
-    case 120:
-        return vkdev_ext120;
-    case 121:
-        return vkdev_ext121;
-    case 122:
-        return vkdev_ext122;
-    case 123:
-        return vkdev_ext123;
-    case 124:
-        return vkdev_ext124;
-    case 125:
-        return vkdev_ext125;
-    case 126:
-        return vkdev_ext126;
-    case 127:
-        return vkdev_ext127;
-    case 128:
-        return vkdev_ext128;
-    case 129:
-        return vkdev_ext129;
-    case 130:
-        return vkdev_ext130;
-    case 131:
-        return vkdev_ext131;
-    case 132:
-        return vkdev_ext132;
-    case 133:
-        return vkdev_ext133;
-    case 134:
-        return vkdev_ext134;
-    case 135:
-        return vkdev_ext135;
-    case 136:
-        return vkdev_ext136;
-    case 137:
-        return vkdev_ext137;
-    case 138:
-        return vkdev_ext138;
-    case 139:
-        return vkdev_ext139;
-    case 140:
-        return vkdev_ext140;
-    case 141:
-        return vkdev_ext141;
-    case 142:
-        return vkdev_ext142;
-    case 143:
-        return vkdev_ext143;
-    case 144:
-        return vkdev_ext144;
-    case 145:
-        return vkdev_ext145;
-    case 146:
-        return vkdev_ext146;
-    case 147:
-        return vkdev_ext147;
-    case 148:
-        return vkdev_ext148;
-    case 149:
-        return vkdev_ext149;
-    case 150:
-        return vkdev_ext150;
-    case 151:
-        return vkdev_ext151;
-    case 152:
-        return vkdev_ext152;
-    case 153:
-        return vkdev_ext153;
-    case 154:
-        return vkdev_ext154;
-    case 155:
-        return vkdev_ext155;
-    case 156:
-        return vkdev_ext156;
-    case 157:
-        return vkdev_ext157;
-    case 158:
-        return vkdev_ext158;
-    case 159:
-        return vkdev_ext159;
-    case 160:
-        return vkdev_ext160;
-    case 161:
-        return vkdev_ext161;
-    case 162:
-        return vkdev_ext162;
-    case 163:
-        return vkdev_ext163;
-    case 164:
-        return vkdev_ext164;
-    case 165:
-        return vkdev_ext165;
-    case 166:
-        return vkdev_ext166;
-    case 167:
-        return vkdev_ext167;
-    case 168:
-        return vkdev_ext168;
-    case 169:
-        return vkdev_ext169;
-    case 170:
-        return vkdev_ext170;
-    case 171:
-        return vkdev_ext171;
-    case 172:
-        return vkdev_ext172;
-    case 173:
-        return vkdev_ext173;
-    case 174:
-        return vkdev_ext174;
-    case 175:
-        return vkdev_ext175;
-    case 176:
-        return vkdev_ext176;
-    case 177:
-        return vkdev_ext177;
-    case 178:
-        return vkdev_ext178;
-    case 179:
-        return vkdev_ext179;
-    case 180:
-        return vkdev_ext180;
-    case 181:
-        return vkdev_ext181;
-    case 182:
-        return vkdev_ext182;
-    case 183:
-        return vkdev_ext183;
-    case 184:
-        return vkdev_ext184;
-    case 185:
-        return vkdev_ext185;
-    case 186:
-        return vkdev_ext186;
-    case 187:
-        return vkdev_ext187;
-    case 188:
-        return vkdev_ext188;
-    case 189:
-        return vkdev_ext189;
-    case 190:
-        return vkdev_ext190;
-    case 191:
-        return vkdev_ext191;
-    case 192:
-        return vkdev_ext192;
-    case 193:
-        return vkdev_ext193;
-    case 194:
-        return vkdev_ext194;
-    case 195:
-        return vkdev_ext195;
-    case 196:
-        return vkdev_ext196;
-    case 197:
-        return vkdev_ext197;
-    case 198:
-        return vkdev_ext198;
-    case 199:
-        return vkdev_ext199;
-    case 200:
-        return vkdev_ext200;
-    case 201:
-        return vkdev_ext201;
-    case 202:
-        return vkdev_ext202;
-    case 203:
-        return vkdev_ext203;
-    case 204:
-        return vkdev_ext204;
-    case 205:
-        return vkdev_ext205;
-    case 206:
-        return vkdev_ext206;
-    case 207:
-        return vkdev_ext207;
-    case 208:
-        return vkdev_ext208;
-    case 209:
-        return vkdev_ext209;
-    case 210:
-        return vkdev_ext210;
-    case 211:
-        return vkdev_ext211;
-    case 212:
-        return vkdev_ext212;
-    case 213:
-        return vkdev_ext213;
-    case 214:
-        return vkdev_ext214;
-    case 215:
-        return vkdev_ext215;
-    case 216:
-        return vkdev_ext216;
-    case 217:
-        return vkdev_ext217;
-    case 218:
-        return vkdev_ext218;
-    case 219:
-        return vkdev_ext219;
-    case 220:
-        return vkdev_ext220;
-    case 221:
-        return vkdev_ext221;
-    case 222:
-        return vkdev_ext222;
-    case 223:
-        return vkdev_ext223;
-    case 224:
-        return vkdev_ext224;
-    case 225:
-        return vkdev_ext225;
-    case 226:
-        return vkdev_ext226;
-    case 227:
-        return vkdev_ext227;
-    case 228:
-        return vkdev_ext228;
-    case 229:
-        return vkdev_ext229;
-    case 230:
-        return vkdev_ext230;
-    case 231:
-        return vkdev_ext231;
-    case 232:
-        return vkdev_ext232;
-    case 233:
-        return vkdev_ext233;
-    case 234:
-        return vkdev_ext234;
-    case 235:
-        return vkdev_ext235;
-    case 236:
-        return vkdev_ext236;
-    case 237:
-        return vkdev_ext237;
-    case 238:
-        return vkdev_ext238;
-    case 239:
-        return vkdev_ext239;
-    case 240:
-        return vkdev_ext240;
-    case 241:
-        return vkdev_ext241;
-    case 242:
-        return vkdev_ext242;
-    case 243:
-        return vkdev_ext243;
-    case 244:
-        return vkdev_ext244;
-    case 245:
-        return vkdev_ext245;
-    case 246:
-        return vkdev_ext246;
-    case 247:
-        return vkdev_ext247;
-    case 248:
-        return vkdev_ext248;
-    case 249:
-        return vkdev_ext249;
+#define CASE_HANDLE(num) case num: return vkdev_ext##num
+        CASE_HANDLE(0);
+        CASE_HANDLE(1);
+        CASE_HANDLE(2);
+        CASE_HANDLE(3);
+        CASE_HANDLE(4);
+        CASE_HANDLE(5);
+        CASE_HANDLE(6);
+        CASE_HANDLE(7);
+        CASE_HANDLE(8);
+        CASE_HANDLE(9);
+        CASE_HANDLE(10);
+        CASE_HANDLE(11);
+        CASE_HANDLE(12);
+        CASE_HANDLE(13);
+        CASE_HANDLE(14);
+        CASE_HANDLE(15);
+        CASE_HANDLE(16);
+        CASE_HANDLE(17);
+        CASE_HANDLE(18);
+        CASE_HANDLE(19);
+        CASE_HANDLE(20);
+        CASE_HANDLE(21);
+        CASE_HANDLE(22);
+        CASE_HANDLE(23);
+        CASE_HANDLE(24);
+        CASE_HANDLE(25);
+        CASE_HANDLE(26);
+        CASE_HANDLE(27);
+        CASE_HANDLE(28);
+        CASE_HANDLE(29);
+        CASE_HANDLE(30);
+        CASE_HANDLE(31);
+        CASE_HANDLE(32);
+        CASE_HANDLE(33);
+        CASE_HANDLE(34);
+        CASE_HANDLE(35);
+        CASE_HANDLE(36);
+        CASE_HANDLE(37);
+        CASE_HANDLE(38);
+        CASE_HANDLE(39);
+        CASE_HANDLE(40);
+        CASE_HANDLE(41);
+        CASE_HANDLE(42);
+        CASE_HANDLE(43);
+        CASE_HANDLE(44);
+        CASE_HANDLE(45);
+        CASE_HANDLE(46);
+        CASE_HANDLE(47);
+        CASE_HANDLE(48);
+        CASE_HANDLE(49);
+        CASE_HANDLE(50);
+        CASE_HANDLE(51);
+        CASE_HANDLE(52);
+        CASE_HANDLE(53);
+        CASE_HANDLE(54);
+        CASE_HANDLE(55);
+        CASE_HANDLE(56);
+        CASE_HANDLE(57);
+        CASE_HANDLE(58);
+        CASE_HANDLE(59);
+        CASE_HANDLE(60);
+        CASE_HANDLE(61);
+        CASE_HANDLE(62);
+        CASE_HANDLE(63);
+        CASE_HANDLE(64);
+        CASE_HANDLE(65);
+        CASE_HANDLE(66);
+        CASE_HANDLE(67);
+        CASE_HANDLE(68);
+        CASE_HANDLE(69);
+        CASE_HANDLE(70);
+        CASE_HANDLE(71);
+        CASE_HANDLE(72);
+        CASE_HANDLE(73);
+        CASE_HANDLE(74);
+        CASE_HANDLE(75);
+        CASE_HANDLE(76);
+        CASE_HANDLE(77);
+        CASE_HANDLE(78);
+        CASE_HANDLE(79);
+        CASE_HANDLE(80);
+        CASE_HANDLE(81);
+        CASE_HANDLE(82);
+        CASE_HANDLE(83);
+        CASE_HANDLE(84);
+        CASE_HANDLE(85);
+        CASE_HANDLE(86);
+        CASE_HANDLE(87);
+        CASE_HANDLE(88);
+        CASE_HANDLE(89);
+        CASE_HANDLE(90);
+        CASE_HANDLE(91);
+        CASE_HANDLE(92);
+        CASE_HANDLE(93);
+        CASE_HANDLE(94);
+        CASE_HANDLE(95);
+        CASE_HANDLE(96);
+        CASE_HANDLE(97);
+        CASE_HANDLE(98);
+        CASE_HANDLE(99);
+        CASE_HANDLE(100);
+        CASE_HANDLE(101);
+        CASE_HANDLE(102);
+        CASE_HANDLE(103);
+        CASE_HANDLE(104);
+        CASE_HANDLE(105);
+        CASE_HANDLE(106);
+        CASE_HANDLE(107);
+        CASE_HANDLE(108);
+        CASE_HANDLE(109);
+        CASE_HANDLE(110);
+        CASE_HANDLE(111);
+        CASE_HANDLE(112);
+        CASE_HANDLE(113);
+        CASE_HANDLE(114);
+        CASE_HANDLE(115);
+        CASE_HANDLE(116);
+        CASE_HANDLE(117);
+        CASE_HANDLE(118);
+        CASE_HANDLE(119);
+        CASE_HANDLE(120);
+        CASE_HANDLE(121);
+        CASE_HANDLE(122);
+        CASE_HANDLE(123);
+        CASE_HANDLE(124);
+        CASE_HANDLE(125);
+        CASE_HANDLE(126);
+        CASE_HANDLE(127);
+        CASE_HANDLE(128);
+        CASE_HANDLE(129);
+        CASE_HANDLE(130);
+        CASE_HANDLE(131);
+        CASE_HANDLE(132);
+        CASE_HANDLE(133);
+        CASE_HANDLE(134);
+        CASE_HANDLE(135);
+        CASE_HANDLE(136);
+        CASE_HANDLE(137);
+        CASE_HANDLE(138);
+        CASE_HANDLE(139);
+        CASE_HANDLE(140);
+        CASE_HANDLE(141);
+        CASE_HANDLE(142);
+        CASE_HANDLE(143);
+        CASE_HANDLE(144);
+        CASE_HANDLE(145);
+        CASE_HANDLE(146);
+        CASE_HANDLE(147);
+        CASE_HANDLE(148);
+        CASE_HANDLE(149);
+        CASE_HANDLE(150);
+        CASE_HANDLE(151);
+        CASE_HANDLE(152);
+        CASE_HANDLE(153);
+        CASE_HANDLE(154);
+        CASE_HANDLE(155);
+        CASE_HANDLE(156);
+        CASE_HANDLE(157);
+        CASE_HANDLE(158);
+        CASE_HANDLE(159);
+        CASE_HANDLE(160);
+        CASE_HANDLE(161);
+        CASE_HANDLE(162);
+        CASE_HANDLE(163);
+        CASE_HANDLE(164);
+        CASE_HANDLE(165);
+        CASE_HANDLE(166);
+        CASE_HANDLE(167);
+        CASE_HANDLE(168);
+        CASE_HANDLE(169);
+        CASE_HANDLE(170);
+        CASE_HANDLE(171);
+        CASE_HANDLE(172);
+        CASE_HANDLE(173);
+        CASE_HANDLE(174);
+        CASE_HANDLE(175);
+        CASE_HANDLE(176);
+        CASE_HANDLE(177);
+        CASE_HANDLE(178);
+        CASE_HANDLE(179);
+        CASE_HANDLE(180);
+        CASE_HANDLE(181);
+        CASE_HANDLE(182);
+        CASE_HANDLE(183);
+        CASE_HANDLE(184);
+        CASE_HANDLE(185);
+        CASE_HANDLE(186);
+        CASE_HANDLE(187);
+        CASE_HANDLE(188);
+        CASE_HANDLE(189);
+        CASE_HANDLE(190);
+        CASE_HANDLE(191);
+        CASE_HANDLE(192);
+        CASE_HANDLE(193);
+        CASE_HANDLE(194);
+        CASE_HANDLE(195);
+        CASE_HANDLE(196);
+        CASE_HANDLE(197);
+        CASE_HANDLE(198);
+        CASE_HANDLE(199);
+        CASE_HANDLE(200);
+        CASE_HANDLE(201);
+        CASE_HANDLE(202);
+        CASE_HANDLE(203);
+        CASE_HANDLE(204);
+        CASE_HANDLE(205);
+        CASE_HANDLE(206);
+        CASE_HANDLE(207);
+        CASE_HANDLE(208);
+        CASE_HANDLE(209);
+        CASE_HANDLE(210);
+        CASE_HANDLE(211);
+        CASE_HANDLE(212);
+        CASE_HANDLE(213);
+        CASE_HANDLE(214);
+        CASE_HANDLE(215);
+        CASE_HANDLE(216);
+        CASE_HANDLE(217);
+        CASE_HANDLE(218);
+        CASE_HANDLE(219);
+        CASE_HANDLE(220);
+        CASE_HANDLE(221);
+        CASE_HANDLE(222);
+        CASE_HANDLE(223);
+        CASE_HANDLE(224);
+        CASE_HANDLE(225);
+        CASE_HANDLE(226);
+        CASE_HANDLE(227);
+        CASE_HANDLE(228);
+        CASE_HANDLE(229);
+        CASE_HANDLE(230);
+        CASE_HANDLE(231);
+        CASE_HANDLE(232);
+        CASE_HANDLE(233);
+        CASE_HANDLE(234);
+        CASE_HANDLE(235);
+        CASE_HANDLE(236);
+        CASE_HANDLE(237);
+        CASE_HANDLE(238);
+        CASE_HANDLE(239);
+        CASE_HANDLE(240);
+        CASE_HANDLE(241);
+        CASE_HANDLE(242);
+        CASE_HANDLE(243);
+        CASE_HANDLE(244);
+        CASE_HANDLE(245);
+        CASE_HANDLE(246);
+        CASE_HANDLE(247);
+        CASE_HANDLE(248);
+        CASE_HANDLE(249);
     }
+
     return NULL;
 }
diff --git a/loader/extensions.c b/loader/extensions.c
index e135644..221924a 100644
--- a/loader/extensions.c
+++ b/loader/extensions.c
@@ -25,9 +25,258 @@
 #include "vk_loader_platform.h"
 #include "loader.h"
 #include "extensions.h"
+#include "table_ops.h"
 #include <vulkan/vk_icd.h>
 #include "wsi.h"
 
+// Definitions for the VK_KHR_get_physical_device_properties2 extension
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
+    VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceFeatures2KHR(unwrapped_phys_dev, pFeatures);
+}
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2KHR(
+    VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceFeatures2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceFeatures2KHR");
+    }
+    icd_term->GetPhysicalDeviceFeatures2KHR(phys_dev_term->phys_dev, pFeatures);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice,
+                                  VkPhysicalDeviceProperties2KHR *pProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceProperties2KHR(unwrapped_phys_dev, pProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    VkPhysicalDeviceProperties2KHR *pProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceProperties2KHR");
+    }
+    icd_term->GetPhysicalDeviceProperties2KHR(phys_dev_term->phys_dev,
+                                              pProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, VkFormat format,
+    VkFormatProperties2KHR *pFormatProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceFormatProperties2KHR(unwrapped_phys_dev, format,
+                                                pFormatProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, VkFormat format,
+    VkFormatProperties2KHR *pFormatProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceFormatProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceFormatProperties2KHR");
+    }
+    icd_term->GetPhysicalDeviceFormatProperties2KHR(phys_dev_term->phys_dev,
+                                                    format, pFormatProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
+    VkImageFormatProperties2KHR *pImageFormatProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    return disp->GetPhysicalDeviceImageFormatProperties2KHR(
+        unwrapped_phys_dev, pImageFormatInfo, pImageFormatProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
+    VkImageFormatProperties2KHR *pImageFormatProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceImageFormatProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceImageFormatProperties2KHR");
+    }
+    return icd_term->GetPhysicalDeviceImageFormatProperties2KHR(
+        phys_dev_term->phys_dev, pImageFormatInfo, pImageFormatProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceQueueFamilyProperties2KHR(
+        unwrapped_phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+terminator_GetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceQueueFamilyProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
+    }
+    icd_term->GetPhysicalDeviceQueueFamilyProperties2KHR(
+        phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
+        pQueueFamilyProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceMemoryProperties2KHR(unwrapped_phys_dev,
+                                                pMemoryProperties);
+}
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceMemoryProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceMemoryProperties2KHR");
+    }
+    icd_term->GetPhysicalDeviceMemoryProperties2KHR(phys_dev_term->phys_dev,
+                                                    pMemoryProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo,
+    uint32_t *pPropertyCount, VkSparseImageFormatProperties2KHR *pProperties) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    disp->GetPhysicalDeviceSparseImageFormatProperties2KHR(
+        unwrapped_phys_dev, pFormatInfo, pPropertyCount, pProperties);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+terminator_GetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo,
+    uint32_t *pPropertyCount, VkSparseImageFormatProperties2KHR *pProperties) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetPhysicalDeviceSparseImageFormatProperties2KHR) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
+    }
+    icd_term->GetPhysicalDeviceSparseImageFormatProperties2KHR(
+        phys_dev_term->phys_dev, pFormatInfo, pPropertyCount, pProperties);
+}
+
+// Definitions for the VK_KHR_maintenance1 extension
+
+VKAPI_ATTR void VKAPI_CALL
+vkTrimCommandPoolKHR(VkDevice device, VkCommandPool commandPool,
+                     VkCommandPoolTrimFlagsKHR flags) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    disp->TrimCommandPoolKHR(device, commandPool, flags);
+}
+
+// Definitions for the VK_EXT_acquire_xlib_display extension
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
+    VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    return disp->AcquireXlibDisplayEXT(unwrapped_phys_dev, dpy, display);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_AcquireXlibDisplayEXT(
+    VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->AcquireXlibDisplayEXT) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkAcquireXlibDisplayEXT");
+    }
+    return icd_term->AcquireXlibDisplayEXT(phys_dev_term->phys_dev, dpy,
+                                           display);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+vkGetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy,
+                           RROutput rrOutput, VkDisplayKHR *pDisplay) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    return disp->GetRandROutputDisplayEXT(unwrapped_phys_dev, dpy, rrOutput,
+                                          pDisplay);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_GetRandROutputDisplayEXT(
+    VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
+    VkDisplayKHR *pDisplay) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->GetRandROutputDisplayEXT) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkGetRandROutputDisplayEXT");
+    }
+    return icd_term->GetRandROutputDisplayEXT(phys_dev_term->phys_dev, dpy,
+                                              rrOutput, pDisplay);
+}
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
 // Definitions for the VK_EXT_debug_marker extension commands which
 // need to have a terminator function
 
@@ -130,9 +379,96 @@
     }
 }
 
+// Definitions for the VK_EXT_direct_mode_display extension
+
+VKAPI_ATTR VkResult VKAPI_CALL
+vkReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    return disp->ReleaseDisplayEXT(unwrapped_phys_dev, display);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_ReleaseDisplayEXT(
+    VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL == icd_term->ReleaseDisplayEXT) {
+        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD associated with VkPhysicalDevice does not support "
+                   "vkReleaseDisplayEXT");
+    }
+    return icd_term->ReleaseDisplayEXT(phys_dev_term->phys_dev, display);
+}
+
+// Definitions for the VK_EXT_display_surface_counter extension
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+    VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+    VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
+    const VkLayerInstanceDispatchTable *disp;
+    VkPhysicalDevice unwrapped_phys_dev =
+        loader_unwrap_physical_device(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    return disp->GetPhysicalDeviceSurfaceCapabilities2EXT(
+        unwrapped_phys_dev, surface, pSurfaceCapabilities);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceSurfaceCapabilities2EXT(
+    VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+    VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
+    struct loader_physical_device_term *phys_dev_term =
+        (struct loader_physical_device_term *)physicalDevice;
+    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
+    if (NULL != icd_term) {
+        if (NULL == icd_term->GetPhysicalDeviceSurfaceCapabilities2EXT) {
+            loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                       0,
+                       "ICD associated with VkPhysicalDevice does not support "
+                       "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
+        }
+        VkIcdSurface *icd_surface = (VkIcdSurface *)(surface);
+        uint8_t icd_index = phys_dev_term->icd_index;
+        if (NULL != icd_surface->real_icd_surfaces) {
+            if (NULL != (void *)icd_surface->real_icd_surfaces[icd_index]) {
+                return icd_term->GetPhysicalDeviceSurfaceCapabilities2EXT(
+                    phys_dev_term->phys_dev,
+                    icd_surface->real_icd_surfaces[icd_index],
+                    pSurfaceCapabilities);
+            }
+        }
+    }
+    return icd_term->GetPhysicalDeviceSurfaceCapabilities2EXT(
+        phys_dev_term->phys_dev, surface, pSurfaceCapabilities);
+}
+
+// Definitions for the VK_AMD_draw_indirect_count extension
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(
+    VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+    VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+    uint32_t stride) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdDrawIndirectCountAMD(commandBuffer, buffer, offset, countBuffer,
+                                  countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(
+    VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+    VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+    uint32_t stride) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdDrawIndexedIndirectCountAMD(commandBuffer, buffer, offset,
+                                         countBuffer, countBufferOffset,
+                                         maxDrawCount, stride);
+}
+
 // Definitions for the VK_NV_external_memory_capabilities extension
 
-LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
+VKAPI_ATTR VkResult VKAPI_CALL
 vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
     VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
@@ -141,7 +477,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
 
     return disp->GetPhysicalDeviceExternalImageFormatPropertiesNV(
         unwrapped_phys_dev, format, type, tiling, usage, flags,
@@ -181,27 +517,6 @@
         externalHandleType, pExternalImageFormatProperties);
 }
 
-// Definitions for the VK_AMD_draw_indirect_count extension
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(
-    VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-    VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
-    uint32_t stride) {
-    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
-    disp->CmdDrawIndirectCountAMD(commandBuffer, buffer, offset, countBuffer,
-                                  countBufferOffset, maxDrawCount, stride);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(
-    VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-    VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
-    uint32_t stride) {
-    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
-    disp->CmdDrawIndexedIndirectCountAMD(commandBuffer, buffer, offset,
-                                         countBuffer, countBufferOffset,
-                                         maxDrawCount, stride);
-}
-
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 
 // Definitions for the VK_NV_external_memory_win32 extension
@@ -288,7 +603,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceGeneratedCommandsPropertiesNVX(unwrapped_phys_dev,
                                                           pFeatures, pLimits);
 }
@@ -311,12 +626,94 @@
     }
 }
 
-// GPA helpers for non-KHR extensions
+// GPA helpers for extensions
 
 bool extension_instance_gpa(struct loader_instance *ptr_instance,
                             const char *name, void **addr) {
     *addr = NULL;
 
+    // Functions for the VK_KHR_get_physical_device_properties2 extension
+
+    if (!strcmp("vkGetPhysicalDeviceFeatures2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceFeatures2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceProperties2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceFormatProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceFormatProperties2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceImageFormatProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceImageFormatProperties2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceQueueFamilyProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceQueueFamilyProperties2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceMemoryProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceMemoryProperties2KHR
+                    : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceSparseImageFormatProperties2KHR", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .khr_get_physical_device_properties2 == 1)
+                    ? (void *)vkGetPhysicalDeviceSparseImageFormatProperties2KHR
+                    : NULL;
+        return true;
+    }
+
+    // Functions for the VK_KHR_maintenance1 extension
+
+    if (!strcmp("vkTrimCommandPoolKHR", name)) {
+        *addr = (void *)vkTrimCommandPoolKHR;
+        return true;
+    }
+
+// Functions for the VK_EXT_acquire_xlib_display extension
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    if (!strcmp("vkAcquireXlibDisplayEXT", name)) {
+        *addr =
+            (ptr_instance->enabled_known_extensions.ext_acquire_xlib_display ==
+             1)
+                ? (void *)vkAcquireXlibDisplayEXT
+                : NULL;
+        return true;
+    }
+
+    if (!strcmp("vkGetRandROutputDisplayEXT", name)) {
+        *addr =
+            (ptr_instance->enabled_known_extensions.ext_acquire_xlib_display ==
+             1)
+                ? (void *)vkGetRandROutputDisplayEXT
+                : NULL;
+        return true;
+    }
+
+#endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
     // Definitions for the VK_EXT_debug_marker extension commands which
     // need to have a terminator function.  Since these are device
     // commands, we always need to return a valid value for them.
@@ -330,12 +727,23 @@
         return true;
     }
 
-    // Functions for the VK_NV_external_memory_capabilities extension
+    // Functions for the VK_EXT_direct_mode_display extension
 
-    if (!strcmp("vkGetPhysicalDeviceExternalImageFormatPropertiesNV", name)) {
+    if (!strcmp("vkReleaseDisplayEXT", name)) {
+        *addr =
+            (ptr_instance->enabled_known_extensions.ext_direct_mode_display ==
+             1)
+                ? (void *)vkReleaseDisplayEXT
+                : NULL;
+        return true;
+    }
+
+    // Functions for the VK_EXT_display_surface_counter extension
+
+    if (!strcmp("vkGetPhysicalDeviceSurfaceCapabilities2EXT", name)) {
         *addr = (ptr_instance->enabled_known_extensions
-                     .nv_external_memory_capabilities == 1)
-                    ? (void *)vkGetPhysicalDeviceExternalImageFormatPropertiesNV
+                     .ext_display_surface_counter == 1)
+                    ? (void *)vkGetPhysicalDeviceSurfaceCapabilities2EXT
                     : NULL;
         return true;
     }
@@ -346,16 +754,23 @@
         *addr = (void *)vkCmdDrawIndirectCountAMD;
         return true;
     }
-
     if (!strcmp("vkCmdDrawIndexedIndirectCountAMD", name)) {
         *addr = (void *)vkCmdDrawIndexedIndirectCountAMD;
         return true;
     }
+    // Functions for the VK_NV_external_memory_capabilities extension
+
+    if (!strcmp("vkGetPhysicalDeviceExternalImageFormatPropertiesNV", name)) {
+        *addr = (ptr_instance->enabled_known_extensions
+                     .nv_external_memory_capabilities == 1)
+                    ? (void *)vkGetPhysicalDeviceExternalImageFormatPropertiesNV
+                    : NULL;
+        return true;
+    }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 
     // Functions for the VK_NV_external_memory_win32 extension
-
     if (!strcmp("vkGetMemoryWin32HandleNV", name)) {
         *addr = (void *)vkGetMemoryWin32HandleNV;
         return true;
@@ -407,14 +822,29 @@
 
 void extensions_create_instance(struct loader_instance *ptr_instance,
                                 const VkInstanceCreateInfo *pCreateInfo) {
-    ptr_instance->enabled_known_extensions.nv_external_memory_capabilities = 0;
-
     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
-                   VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME) == 0) {
+        if (0 ==
+            strcmp(pCreateInfo->ppEnabledExtensionNames[i],
+                   VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+            ptr_instance->enabled_known_extensions
+                .khr_get_physical_device_properties2 = 1;
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i],
+                               VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME)) {
+            ptr_instance->enabled_known_extensions.ext_acquire_xlib_display = 1;
+#endif
+        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i],
+                               VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME)) {
+            ptr_instance->enabled_known_extensions.ext_direct_mode_display = 1;
+        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i],
+                               VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) {
+            ptr_instance->enabled_known_extensions.ext_display_surface_counter =
+                1;
+        } else if (0 ==
+                   strcmp(pCreateInfo->ppEnabledExtensionNames[i],
+                          VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) {
             ptr_instance->enabled_known_extensions
                 .nv_external_memory_capabilities = 1;
-            return;
         }
     }
 }
diff --git a/loader/extensions.h b/loader/extensions.h
index 7175965..b94aaf9 100644
--- a/loader/extensions.h
+++ b/loader/extensions.h
@@ -28,8 +28,69 @@
 void extensions_create_instance(struct loader_instance *ptr_instance,
                                 const VkInstanceCreateInfo *pCreateInfo);
 
-// Definitions for the VK_EXT_debug_marker extension
+// Instance extension terminators for the VK_KHR_get_physical_device_properties2
+// extension
 
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2KHR(
+    VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    VkPhysicalDeviceProperties2KHR *pProperties);
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice, VkFormat format,
+    VkFormatProperties2KHR *pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
+    VkImageFormatProperties2KHR *pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL
+terminator_GetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2KHR *pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL
+terminator_GetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo,
+    uint32_t *pPropertyCount, VkSparseImageFormatProperties2KHR *pProperties);
+
+// Instance extension terminators for the VK_EXT_acquire_xlib_display
+// extension
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VKAPI_ATTR VkResult VKAPI_CALL terminator_AcquireXlibDisplayEXT(
+    VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display);
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_GetRandROutputDisplayEXT(
+    VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
+    VkDisplayKHR *pDisplay);
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
+// Instance extension terminators for the VK_EXT_direct_mode_display
+// extension
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_ReleaseDisplayEXT(
+    VkPhysicalDevice physicalDevice, VkDisplayKHR display);
+
+// Instance extension terminators for the VK_EXT_display_surface_counter
+// extension
+
+VKAPI_ATTR VkResult VKAPI_CALL
+terminator_GetPhysicalDeviceSurfaceCapabilities2EXT(
+    VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+    VkSurfaceCapabilities2EXT *pSurfaceCapabilities);
+
+// Device extension terminators for the VK_NV_external_memory_capabilities
+// extension
 
 VKAPI_ATTR VkResult VKAPI_CALL terminator_DebugMarkerSetObjectTagEXT(
     VkDevice device, VkDebugMarkerObjectTagInfoEXT *pTagInfo);
@@ -37,7 +98,8 @@
 VKAPI_ATTR VkResult VKAPI_CALL terminator_DebugMarkerSetObjectNameEXT(
     VkDevice device, VkDebugMarkerObjectNameInfoEXT *pNameInfo);
 
-// Definitions for the VK_NV_external_memory_capabilities extension
+// Instance extension terminators for the VK_NV_external_memory_capabilities
+// extension
 
 VKAPI_ATTR VkResult VKAPI_CALL
 terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV(
diff --git a/loader/get_proc_addr.png b/loader/get_proc_addr.png
deleted file mode 100644
index a11c164..0000000
--- a/loader/get_proc_addr.png
+++ /dev/null
Binary files differ
diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h
index 5089b59..c7e7ba2 100644
--- a/loader/gpa_helper.h
+++ b/loader/gpa_helper.h
@@ -308,6 +308,11 @@
     if (extension_instance_gpa(inst, funcName, &addr))
         return addr;
 
+    // Unknown physical device extensions
+    if (loader_phys_dev_ext_gpa(inst, funcName, true, &addr, NULL))
+        return addr;
+
+    // Unknown device extensions
     addr = loader_dev_ext_gpa(inst, funcName);
     return addr;
 }
@@ -327,36 +332,6 @@
     return NULL;
 }
 
-/* These functions require special handling by the loader.
-*  They are not just generic trampoline code entrypoints.
-*  Thus GPA must return loader entrypoint for these instead of first function
-*  in the chain. */
-static inline void *loader_non_passthrough_gipa(const char *name) {
-    if (!name || name[0] != 'v' || name[1] != 'k')
-        return NULL;
-
-    name += 2;
-    if (!strcmp(name, "CreateInstance"))
-        return (void *)vkCreateInstance;
-    if (!strcmp(name, "DestroyInstance"))
-        return (void *)vkDestroyInstance;
-    if (!strcmp(name, "GetDeviceProcAddr"))
-        return (void *)vkGetDeviceProcAddr;
-    // remove once no longer locks
-    if (!strcmp(name, "EnumeratePhysicalDevices"))
-        return (void *)vkEnumeratePhysicalDevices;
-    if (!strcmp(name, "EnumerateDeviceExtensionProperties"))
-        return (void *)vkEnumerateDeviceExtensionProperties;
-    if (!strcmp(name, "EnumerateDeviceLayerProperties"))
-        return (void *)vkEnumerateDeviceLayerProperties;
-    if (!strcmp(name, "GetInstanceProcAddr"))
-        return (void *)vkGetInstanceProcAddr;
-    if (!strcmp(name, "CreateDevice"))
-        return (void *)vkCreateDevice;
-
-    return NULL;
-}
-
 static inline void *loader_non_passthrough_gdpa(const char *name) {
     if (!name || name[0] != 'v' || name[1] != 'k')
         return NULL;
diff --git a/loader/images/function_device_chain.png b/loader/images/function_device_chain.png
new file mode 100644
index 0000000..62ba7a3
--- /dev/null
+++ b/loader/images/function_device_chain.png
Binary files differ
diff --git a/loader/images/function_device_chain_white.png b/loader/images/function_device_chain_white.png
new file mode 100644
index 0000000..b6107a8
--- /dev/null
+++ b/loader/images/function_device_chain_white.png
Binary files differ
diff --git a/loader/images/function_instance_chain.png b/loader/images/function_instance_chain.png
new file mode 100644
index 0000000..b79fd96
--- /dev/null
+++ b/loader/images/function_instance_chain.png
Binary files differ
diff --git a/loader/images/function_instance_chain_white.png b/loader/images/function_instance_chain_white.png
new file mode 100644
index 0000000..48705a2
--- /dev/null
+++ b/loader/images/function_instance_chain_white.png
Binary files differ
diff --git a/loader/images/high_level_loader.png b/loader/images/high_level_loader.png
new file mode 100644
index 0000000..391abb7
--- /dev/null
+++ b/loader/images/high_level_loader.png
Binary files differ
diff --git a/loader/images/high_level_loader_white.png b/loader/images/high_level_loader_white.png
new file mode 100644
index 0000000..c83cade
--- /dev/null
+++ b/loader/images/high_level_loader_white.png
Binary files differ
diff --git a/loader/images/loader_device_chain_app.png b/loader/images/loader_device_chain_app.png
new file mode 100644
index 0000000..764fcd6
--- /dev/null
+++ b/loader/images/loader_device_chain_app.png
Binary files differ
diff --git a/loader/images/loader_device_chain_app_white.png b/loader/images/loader_device_chain_app_white.png
new file mode 100644
index 0000000..8bd28ee
--- /dev/null
+++ b/loader/images/loader_device_chain_app_white.png
Binary files differ
diff --git a/loader/images/loader_device_chain_loader.png b/loader/images/loader_device_chain_loader.png
new file mode 100644
index 0000000..d226a3e
--- /dev/null
+++ b/loader/images/loader_device_chain_loader.png
Binary files differ
diff --git a/loader/images/loader_device_chain_loader_white.png b/loader/images/loader_device_chain_loader_white.png
new file mode 100644
index 0000000..993a555
--- /dev/null
+++ b/loader/images/loader_device_chain_loader_white.png
Binary files differ
diff --git a/loader/images/loader_instance_chain.png b/loader/images/loader_instance_chain.png
new file mode 100644
index 0000000..8bc06d0
--- /dev/null
+++ b/loader/images/loader_instance_chain.png
Binary files differ
diff --git a/loader/images/loader_instance_chain_white.png b/loader/images/loader_instance_chain_white.png
new file mode 100644
index 0000000..4c3c066
--- /dev/null
+++ b/loader/images/loader_instance_chain_white.png
Binary files differ
diff --git a/loader/images/loader_layer_order.png b/loader/images/loader_layer_order.png
new file mode 100644
index 0000000..80b9ea4
--- /dev/null
+++ b/loader/images/loader_layer_order.png
Binary files differ
diff --git a/loader/images/loader_layer_order_white.png b/loader/images/loader_layer_order_white.png
new file mode 100644
index 0000000..ed25dc9
--- /dev/null
+++ b/loader/images/loader_layer_order_white.png
Binary files differ
diff --git a/loader/instance_call_chain.png b/loader/instance_call_chain.png
deleted file mode 100644
index 848b726..0000000
--- a/loader/instance_call_chain.png
+++ /dev/null
Binary files differ
diff --git a/loader/loader.c b/loader/loader.c
index 351bf2ec..24758f4 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -1,8 +1,8 @@
 /*
  *
- * Copyright (c) 2014-2016 The Khronos Group Inc.
- * Copyright (c) 2014-2016 Valve Corporation
- * Copyright (c) 2014-2016 LunarG, Inc.
+ * Copyright (c) 2014-2017 The Khronos Group Inc.
+ * Copyright (c) 2014-2017 Valve Corporation
+ * Copyright (c) 2014-2017 LunarG, Inc.
  * Copyright (C) 2015 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +20,7 @@
  *
  * Author: Jon Ashburn <jon@lunarg.com>
  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: Mark Young <marky@lunarg.com>
  *
  */
 
@@ -115,11 +116,6 @@
         terminator_GetPhysicalDeviceSurfaceFormatsKHR,
     .GetPhysicalDeviceSurfacePresentModesKHR =
         terminator_GetPhysicalDeviceSurfacePresentModesKHR,
-    .CreateDebugReportCallbackEXT = terminator_CreateDebugReportCallback,
-    .DestroyDebugReportCallbackEXT = terminator_DestroyDebugReportCallback,
-    .DebugReportMessageEXT = terminator_DebugReportMessage,
-    .GetPhysicalDeviceExternalImageFormatPropertiesNV =
-        terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV,
 #ifdef VK_USE_PLATFORM_MIR_KHR
     .CreateMirSurfaceKHR = terminator_CreateMirSurfaceKHR,
     .GetPhysicalDeviceMirPresentationSupportKHR =
@@ -159,6 +155,43 @@
     .GetDisplayPlaneCapabilitiesKHR = terminator_GetDisplayPlaneCapabilitiesKHR,
     .CreateDisplayPlaneSurfaceKHR = terminator_CreateDisplayPlaneSurfaceKHR,
 
+    // KHR_get_physical_device_properties2
+    .GetPhysicalDeviceFeatures2KHR = terminator_GetPhysicalDeviceFeatures2KHR,
+    .GetPhysicalDeviceProperties2KHR =
+        terminator_GetPhysicalDeviceProperties2KHR,
+    .GetPhysicalDeviceFormatProperties2KHR =
+        terminator_GetPhysicalDeviceFormatProperties2KHR,
+    .GetPhysicalDeviceImageFormatProperties2KHR =
+        terminator_GetPhysicalDeviceImageFormatProperties2KHR,
+    .GetPhysicalDeviceQueueFamilyProperties2KHR =
+        terminator_GetPhysicalDeviceQueueFamilyProperties2KHR,
+    .GetPhysicalDeviceMemoryProperties2KHR =
+        terminator_GetPhysicalDeviceMemoryProperties2KHR,
+    .GetPhysicalDeviceSparseImageFormatProperties2KHR =
+        terminator_GetPhysicalDeviceSparseImageFormatProperties2KHR,
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // EXT_acquire_xlib_display
+    .AcquireXlibDisplayEXT = terminator_AcquireXlibDisplayEXT,
+    .GetRandROutputDisplayEXT = terminator_GetRandROutputDisplayEXT,
+#endif
+
+    // EXT_debug_report
+    .CreateDebugReportCallbackEXT = terminator_CreateDebugReportCallback,
+    .DestroyDebugReportCallbackEXT = terminator_DestroyDebugReportCallback,
+    .DebugReportMessageEXT = terminator_DebugReportMessage,
+
+    // EXT_direct_mode_display
+    .ReleaseDisplayEXT = terminator_ReleaseDisplayEXT,
+
+    // EXT_display_surface_counter
+    .GetPhysicalDeviceSurfaceCapabilities2EXT =
+        terminator_GetPhysicalDeviceSurfaceCapabilities2EXT,
+
+    // NV_external_memory_capabilities
+    .GetPhysicalDeviceExternalImageFormatPropertiesNV =
+        terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV,
+
     // NVX_device_generated_commands
     .GetPhysicalDeviceGeneratedCommandsPropertiesNVX =
         terminator_GetPhysicalDeviceGeneratedCommandsPropertiesNVX,
@@ -187,9 +220,18 @@
 #ifdef VK_USE_PLATFORM_WIN32_KHR
     VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
 #endif
+    VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME,
+#endif
     VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
-    VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
+    VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME,
+    VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME,
     VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME,
+#ifdef VK_USE_PLATFORM_VI_NN
+    VK_NN_VI_SURFACE_EXTENSION_NAME,
+#endif
+    VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
     NULL};
 
 LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
@@ -844,6 +886,10 @@
     }
 
     ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
+    if (NULL == ext_props) {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
 
     res = fp_get_props(NULL, &count, ext_props);
     if (res != VK_SUCCESS) {
@@ -1424,9 +1470,9 @@
                  dev = dev->next)
                 // Value comparison of device prevents object wrapping by layers
                 if (loader_get_dispatch(dev->icd_device) ==
-                    loader_get_dispatch(device) ||
+                        loader_get_dispatch(device) ||
                     loader_get_dispatch(dev->chain_device) ==
-                    loader_get_dispatch(device)) {
+                        loader_get_dispatch(device)) {
                     *found_dev = dev;
                     if (NULL != icd_index) {
                         *icd_index = index;
@@ -1568,10 +1614,6 @@
  * the negotiation API is not supported by the ICD
  * @return  bool indicating true if the selected interface version is supported
  *          by the loader, false indicates the version is not supported
- * version 0   doesn't support vk_icdGetInstanceProcAddr nor
- *             vk_icdNegotiateLoaderICDInterfaceVersion
- * version 1   supports vk_icdGetInstanceProcAddr
- * version 2   supports vk_icdNegotiateLoaderICDInterfaceVersion
  */
 bool loader_get_icd_interface_version(
     PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version,
@@ -1645,6 +1687,7 @@
     PFN_vkCreateInstance fp_create_inst;
     PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
     PFN_vkGetInstanceProcAddr fp_get_proc_addr;
+    PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
     PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
     struct loader_scanned_icd *new_scanned_icd;
     uint32_t interface_vers;
@@ -1715,8 +1758,9 @@
         }
     } else {
         // Use newer interface version 1 or later
-        if (interface_vers == 0)
+        if (interface_vers == 0) {
             interface_vers = 1;
+        }
 
         fp_create_inst =
             (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
@@ -1739,6 +1783,8 @@
                        filename);
             goto out;
         }
+        fp_get_phys_dev_proc_addr =
+            loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
     }
 
     // check for enough capacity
@@ -1759,11 +1805,12 @@
         // double capacity
         icd_tramp_list->capacity *= 2;
     }
-    new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
 
+    new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
     new_scanned_icd->handle = handle;
     new_scanned_icd->api_version = api_version;
     new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
+    new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
     new_scanned_icd->EnumerateInstanceExtensionProperties =
         fp_get_inst_ext_props;
     new_scanned_icd->CreateInstance = fp_create_inst;
@@ -1814,10 +1861,6 @@
     LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
     LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
     LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
-    LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
-    LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
-    LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
-    LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
     LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
     LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
     LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
@@ -1851,6 +1894,37 @@
     LOOKUP_GIPA(CreateWaylandSurfaceKHR, false);
     LOOKUP_GIPA(GetPhysicalDeviceWaylandPresentationSupportKHR, false);
 #endif
+    LOOKUP_GIPA(CreateSharedSwapchainsKHR, false);
+
+    // KHR_get_physical_device_properties2
+    LOOKUP_GIPA(GetPhysicalDeviceFeatures2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceProperties2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceFormatProperties2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties2KHR, false);
+    LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties2KHR, false);
+    // EXT_debug_marker (items needing a trampoline/terminator)
+    LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
+    LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // EXT_acquire_xlib_display
+    LOOKUP_GIPA(AcquireXlibDisplayEXT, false);
+    LOOKUP_GIPA(GetRandROutputDisplayEXT, false);
+#endif
+
+    // EXT_debug_report
+    LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
+    LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
+    LOOKUP_GIPA(DebugReportMessageEXT, false);
+
+    // EXT_direct_mode_display
+    LOOKUP_GIPA(ReleaseDisplayEXT, false);
+
+    // EXT_display_surface_counter
+    LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilities2EXT, false);
+
     // NV_external_memory_capabilities
     LOOKUP_GIPA(GetPhysicalDeviceExternalImageFormatPropertiesNV, false);
     // NVX_device_generated_commands
@@ -2324,10 +2398,20 @@
     }
 }
 
-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) {
+// This structure is used to store the json file version
+// in a more managable way.
+typedef struct {
+    uint16_t major;
+    uint16_t minor;
+    uint16_t patch;
+} layer_json_version;
+
+static void
+loader_read_json_layer(const struct loader_instance *inst,
+                       struct loader_layer_list *layer_instance_list,
+                       cJSON *layer_node, layer_json_version version,
+                       cJSON *item, cJSON *disable_environment,
+                       bool is_implicit, char *filename) {
     char *temp;
     char *name, *type, *library_path, *api_version;
     char *implementation_version, *description;
@@ -2394,7 +2478,7 @@
 #undef GET_JSON_ITEM
 #undef GET_JSON_OBJECT
 
-    // add list entry
+    // Add list entry
     struct loader_layer_properties *props = NULL;
     if (!strcmp(type, "DEVICE")) {
         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
@@ -2429,13 +2513,13 @@
     char *fullpath = props->lib_name;
     char *rel_base;
     if (loader_platform_is_path(library_path)) {
-        // a relative or absolute 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
+        // A filename which is assumed in a system directory
         loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
                             MAX_STRING_SIZE, fullpath);
     }
@@ -2489,40 +2573,69 @@
 
     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;
+    cJSON *entrypoints = NULL;
+    char *vkGetInstanceProcAddr = NULL;
+    char *vkGetDeviceProcAddr = NULL;
+    char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
+    char *spec_version = NULL;
+    char **entry_array = NULL;
     entrypoints = NULL;
-    entry_array = NULL;
     int i, j;
 
-    /**
-    * functions
-    *     vkGetInstanceProcAddr
-    *     vkGetDeviceProcAddr
-    */
+    // Layer interface functions
+    //    vkGetInstanceProcAddr
+    //    vkGetDeviceProcAddr
+    //    vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
     GET_JSON_OBJECT(layer_node, functions)
     if (functions != NULL) {
+        if (version.major > 1 || version.minor >= 1) {
+            GET_JSON_ITEM(functions, vkNegotiateLoaderLayerInterfaceVersion)
+            if (vkNegotiateLoaderLayerInterfaceVersion != NULL)
+                strncpy(props->functions.str_negotiate_interface,
+                        vkNegotiateLoaderLayerInterfaceVersion,
+                        sizeof(props->functions.str_negotiate_interface));
+            props->functions.str_negotiate_interface
+                [sizeof(props->functions.str_negotiate_interface) - 1] = '\0';
+        } else {
+            props->functions.str_negotiate_interface[0] = '\0';
+        }
         GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
         GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
-        if (vkGetInstanceProcAddr != NULL)
+        if (vkGetInstanceProcAddr != NULL) {
             strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
                     sizeof(props->functions.str_gipa));
+            if (version.major > 1 || version.minor >= 1) {
+                loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                           "Indicating layer-specific vkGetInstanceProcAddr "
+                           "function is deprecated starting with JSON file "
+                           "version 1.1.0.  Instead, use the new "
+                           "vkNegotiateLayerInterfaceVersion function to "
+                           "return the GetInstanceProcAddr function for this"
+                           "layer");
+            }
+        }
         props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
-        if (vkGetDeviceProcAddr != NULL)
+        if (vkGetDeviceProcAddr != NULL) {
             strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
                     sizeof(props->functions.str_gdpa));
+            if (version.major > 1 || version.minor >= 1) {
+                loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                           "Indicating layer-specific vkGetDeviceProcAddr "
+                           "function is deprecated starting with JSON file "
+                           "version 1.1.0.  Instead, use the new "
+                           "vkNegotiateLayerInterfaceVersion function to "
+                           "return the GetDeviceProcAddr function for this"
+                           "layer");
+            }
+        }
         props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
     }
-    /**
-    * instance_extensions
-    * array of
-    *     name
-    *     spec_version
-    */
+
+    // instance_extensions
+    //   array of {
+    //     name
+    //     spec_version
+    //   }
     GET_JSON_OBJECT(layer_node, instance_extensions)
     if (instance_extensions != NULL) {
         int count = cJSON_GetArraySize(instance_extensions);
@@ -2549,13 +2662,13 @@
             }
         }
     }
-    /**
-    * device_extensions
-    * array of
-    *     name
-    *     spec_version
-    *     entrypoints
-    */
+
+    // 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);
@@ -2626,6 +2739,23 @@
 #undef GET_JSON_OBJECT
 }
 
+static inline bool is_valid_layer_json_version(const layer_json_version *layer_json) {
+    // Supported versions are: 1.0.0, 1.0.1, and 1.1.0.
+    if ((layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch == 0) ||
+        (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
+        return true;
+    }
+    return false;
+}
+
+static inline bool layer_json_supports_layers_tag(const layer_json_version *layer_json) {
+    // Supported versions started in 1.0.1, so anything newer
+    if ((layer_json->major > 1 || layer_json->minor > 0 || layer_json->patch > 1)) {
+        return true;
+    }
+    return false;
+}
+
 /**
  * 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
@@ -2641,19 +2771,13 @@
 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
-     */
+    // The following Fields in layer manifest file that are required:
+    //   - “file_format_version”
+    //   - If more than one "layer" object are used, then the "layers" array is
+    //     requred
 
     cJSON *item, *layers_node, *layer_node;
-    uint16_t file_major_vers = 0;
-    uint16_t file_minor_vers = 0;
-    uint16_t file_patch_vers = 0;
+    layer_json_version json_version;
     char *vers_tok;
     cJSON *disable_environment = NULL;
     item = cJSON_GetObjectItem(json, "file_format_version");
@@ -2669,30 +2793,31 @@
     // 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 = (uint16_t)atoi(vers_tok);
+        json_version.major = (uint16_t)atoi(vers_tok);
         vers_tok = strtok(NULL, ".\"\n\r");
         if (NULL != vers_tok) {
-            file_minor_vers = (uint16_t)atoi(vers_tok);
+            json_version.minor = (uint16_t)atoi(vers_tok);
             vers_tok = strtok(NULL, ".\"\n\r");
             if (NULL != vers_tok) {
-                file_patch_vers = (uint16_t)atoi(vers_tok);
+                json_version.patch = (uint16_t)atoi(vers_tok);
             }
         }
     }
-    if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
+
+    if (!is_valid_layer_json_version(&json_version)) {
         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
-                   "loader_add_layer_properties: Unexpected manifest file "
-                   "version (expected 1.0.0 or 1.0.1) in %s, may cause "
-                   "errors",
-                   filename);
+                   "loader_add_layer_properties: %s invalid layer "
+                   " manifest file version %d.%d.%d.  May cause errors.",
+                   filename, json_version.major, json_version.minor,
+                   json_version.patch);
     }
     cJSON_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) {
+        if (!layer_json_supports_layers_tag(&json_version)) {
             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
                        "loader_add_layer_properties: \'layers\' tag not "
                        "supported until file version 1.0.1, but %s is "
@@ -2709,8 +2834,9 @@
                            curLayer, filename);
                 return;
             }
-            loader_read_json_layer(inst, layer_instance_list, layer_node, item,
-                                   disable_environment, is_implicit, filename);
+            loader_read_json_layer(inst, layer_instance_list, layer_node,
+                                   json_version, item, disable_environment,
+                                   is_implicit, filename);
         }
     } else {
         // Otherwise, try to read in individual layers
@@ -2730,14 +2856,11 @@
             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))) {
+
+        // 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 && layer_json_supports_layers_tag(&json_version)) {
             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                        "loader_add_layer_properties: Multiple \'layer\' nodes"
                        " are deprecated starting in file version \"1.0.1\".  "
@@ -2746,8 +2869,8 @@
         } else {
             do {
                 loader_read_json_layer(inst, layer_instance_list, layer_node,
-                                       item, disable_environment, is_implicit,
-                                       filename);
+                                       json_version, item, disable_environment,
+                                       is_implicit, filename);
                 layer_node = layer_node->next;
             } while (layer_node != NULL);
         }
@@ -2788,7 +2911,7 @@
                           bool is_layer, bool warn_if_not_present,
                           const char *location, const char *home_location,
                           struct loader_manifest_files *out_files) {
-    const char *override = NULL;
+    const char * override = NULL;
     char *override_getenv = NULL;
     char *loc, *orig_loc = NULL;
     char *reg = NULL;
@@ -3138,8 +3261,8 @@
     }
 
     // Get a list of manifest files for ICDs
-    res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false,
-                                    true, DEFAULT_VK_DRIVERS_INFO,
+    res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false, true,
+                                    DEFAULT_VK_DRIVERS_INFO,
                                     HOME_VK_DRIVERS_INFO, &manifest_files);
     if (VK_SUCCESS != res || manifest_files.count == 0) {
         goto out;
@@ -3487,13 +3610,82 @@
 }
 
 static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+loader_gpdpa_instance_internal(VkInstance inst, const char *pName) {
+    // inst is not wrapped
+    if (inst == VK_NULL_HANDLE) {
+        return NULL;
+    }
+    VkLayerInstanceDispatchTable *disp_table =
+        *(VkLayerInstanceDispatchTable **)inst;
+    void *addr;
+
+    if (disp_table == NULL)
+        return NULL;
+
+    bool found_name;
+    addr =
+        loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
+    if (found_name) {
+        return addr;
+    }
+
+    if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, true, NULL, &addr))
+        return addr;
+
+    // Don't call down the chain, this would be an infinite loop
+    loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+               "loader_gpdpa_instance_internal() unrecognized name %s", pName);
+    return NULL;
+}
+
+static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
+    // inst is not wrapped
+    if (inst == VK_NULL_HANDLE) {
+        return NULL;
+    }
+    VkLayerInstanceDispatchTable *disp_table =
+        *(VkLayerInstanceDispatchTable **)inst;
+    void *addr;
+
+    if (disp_table == NULL)
+        return NULL;
+
+    bool found_name;
+    addr =
+        loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
+    if (found_name) {
+        return addr;
+    }
+
+    // Get the terminator, but don't perform checking since it should already
+    // have been setup if we get here.
+    if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, false, NULL,
+                                &addr)) {
+        return addr;
+    }
+
+    // Don't call down the chain, this would be an infinite loop
+    loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+               "loader_gpdpa_instance_terminator() unrecognized name %s",
+               pName);
+    return NULL;
+}
+
+static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
 loader_gpa_instance_internal(VkInstance inst, const char *pName) {
-    if (!strcmp(pName, "vkGetInstanceProcAddr"))
-        return (void *)loader_gpa_instance_internal;
-    if (!strcmp(pName, "vkCreateInstance"))
-        return (void *)terminator_CreateInstance;
-    if (!strcmp(pName, "vkCreateDevice"))
-        return (void *)terminator_CreateDevice;
+    if (!strcmp(pName, "vkGetInstanceProcAddr")) {
+        return (PFN_vkVoidFunction)loader_gpa_instance_internal;
+    }
+    if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
+        return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
+    }
+    if (!strcmp(pName, "vkCreateInstance")) {
+        return (PFN_vkVoidFunction)terminator_CreateInstance;
+    }
+    if (!strcmp(pName, "vkCreateDevice")) {
+        return (PFN_vkVoidFunction)terminator_CreateDevice;
+    }
 
     // inst is not wrapped
     if (inst == VK_NULL_HANDLE) {
@@ -3537,6 +3729,8 @@
         return (PFN_vkVoidFunction)loader_gpa_device_internal;
     } else if (!strcmp(pName, "vkCreateSwapchainKHR")) {
         return (PFN_vkVoidFunction)terminator_vkCreateSwapchainKHR;
+    } else if (!strcmp(pName, "vkCreateSharedSwapchainsKHR")) {
+        return (PFN_vkVoidFunction)terminator_vkCreateSharedSwapchainsKHR;
     } else if (!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
         return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
     } else if (!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
@@ -3592,15 +3786,15 @@
  */
 void loader_init_dispatch_dev_ext(struct loader_instance *inst,
                                   struct loader_device *dev) {
-    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
-        if (inst->disp_hash[i].func_name != NULL)
+    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
+        if (inst->dev_ext_disp_hash[i].func_name != NULL)
             loader_init_dispatch_dev_ext_entry(inst, dev, i,
-                                               inst->disp_hash[i].func_name);
+                                               inst->dev_ext_disp_hash[i].func_name);
     }
 }
 
-static bool loader_check_icds_for_address(struct loader_instance *inst,
-                                          const char *funcName) {
+static bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst,
+                                                  const char *funcName) {
     struct loader_icd_term *icd_term;
     icd_term = inst->icd_terms;
     while (NULL != icd_term) {
@@ -3614,7 +3808,7 @@
     return false;
 }
 
-static bool loader_check_layer_list_for_address(
+static bool loader_check_layer_list_for_dev_ext_address(
     const struct loader_layer_list *const layers, const char *funcName) {
     // Iterate over the layers.
     for (uint32_t layer = 0; layer < layers->count; ++layer) {
@@ -3639,32 +3833,35 @@
 }
 
 static void loader_free_dev_ext_table(struct loader_instance *inst) {
-    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
-        loader_instance_heap_free(inst, inst->disp_hash[i].func_name);
-        loader_instance_heap_free(inst, inst->disp_hash[i].list.index);
+    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
+        loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].func_name);
+        loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].list.index);
     }
-    memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
+    memset(inst->dev_ext_disp_hash, 0, sizeof(inst->dev_ext_disp_hash));
 }
 
 static bool loader_add_dev_ext_table(struct loader_instance *inst,
                                      uint32_t *ptr_idx, const char *funcName) {
     uint32_t i;
     uint32_t idx = *ptr_idx;
-    struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
+    struct loader_dispatch_hash_list *list = &inst->dev_ext_disp_hash[idx].list;
 
-    if (!inst->disp_hash[idx].func_name) {
+    if (!inst->dev_ext_disp_hash[idx].func_name) {
         // no entry here at this idx, so use it
         assert(list->capacity == 0);
-        inst->disp_hash[idx].func_name = (char *)loader_instance_heap_alloc(
-            inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-        if (inst->disp_hash[idx].func_name == NULL) {
+        inst->dev_ext_disp_hash[idx].func_name =
+            (char *)loader_instance_heap_alloc(
+                inst, strlen(funcName) + 1,
+                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+        if (inst->dev_ext_disp_hash[idx].func_name == NULL) {
             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                        "loader_add_dev_ext_table: Failed to allocate memory "
                        "for func_name %s",
                        funcName);
             return false;
         }
-        strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
+        strncpy(inst->dev_ext_disp_hash[idx].func_name, funcName,
+                strlen(funcName) + 1);
         return true;
     }
 
@@ -3696,14 +3893,15 @@
     }
 
     // find an unused index in the hash table and use it
-    i = (idx + 1) % MAX_NUM_DEV_EXTS;
+    i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
     do {
-        if (!inst->disp_hash[i].func_name) {
-            assert(inst->disp_hash[i].list.capacity == 0);
-            inst->disp_hash[i].func_name = (char *)loader_instance_heap_alloc(
-                inst, strlen(funcName) + 1,
-                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-            if (inst->disp_hash[i].func_name == NULL) {
+        if (!inst->dev_ext_disp_hash[i].func_name) {
+            assert(inst->dev_ext_disp_hash[i].list.capacity == 0);
+            inst->dev_ext_disp_hash[i].func_name =
+                (char *)loader_instance_heap_alloc(
+                    inst, strlen(funcName) + 1,
+                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+            if (inst->dev_ext_disp_hash[i].func_name == NULL) {
                 loader_log(
                     inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                     "loader_add_dev_ext_table: Failed to allocate memory "
@@ -3711,14 +3909,14 @@
                     funcName);
                 return false;
             }
-            strncpy(inst->disp_hash[i].func_name, funcName,
+            strncpy(inst->dev_ext_disp_hash[i].func_name, funcName,
                     strlen(funcName) + 1);
             list->index[list->count] = i;
             list->count++;
             *ptr_idx = i;
             return true;
         }
-        i = (i + 1) % MAX_NUM_DEV_EXTS;
+        i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
     } while (i != idx);
 
     loader_log(
@@ -3732,16 +3930,15 @@
 static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
                                          uint32_t *idx, const char *funcName) {
     uint32_t alt_idx;
-    if (inst->disp_hash[*idx].func_name &&
-        !strcmp(inst->disp_hash[*idx].func_name, funcName))
+    if (inst->dev_ext_disp_hash[*idx].func_name &&
+        !strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName))
         return true;
 
     // funcName wasn't at the primary spot in the hash table
     // search the list of secondary locations (shallow search, not deep search)
-    for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
-        alt_idx = inst->disp_hash[*idx].list.index[i];
-        if (inst->disp_hash[*idx].func_name &&
-            !strcmp(inst->disp_hash[*idx].func_name, funcName)) {
+    for (uint32_t i = 0; i < inst->dev_ext_disp_hash[*idx].list.count; i++) {
+        alt_idx = inst->dev_ext_disp_hash[*idx].list.index[i];
+        if (!strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) {
             *idx = alt_idx;
             return true;
         }
@@ -3772,16 +3969,15 @@
     uint32_t idx;
     uint32_t seed = 0;
 
-    idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
+    idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
 
     if (loader_name_in_dev_ext_table(inst, &idx, funcName))
         // found funcName already in hash
         return loader_get_dev_ext_trampoline(idx);
 
     // Check if funcName is supported in either ICDs or a layer library
-    if (!loader_check_icds_for_address(inst, funcName) &&
-        !loader_check_layer_list_for_address(&inst->instance_layer_list,
-                                             funcName)) {
+    if (!loader_check_icds_for_dev_ext_address(inst, funcName) &&
+        !loader_check_layer_list_for_dev_ext_address(&inst->instance_layer_list, funcName)) {
         // if support found in layers continue on
         return NULL;
     }
@@ -3796,6 +3992,275 @@
     return NULL;
 }
 
+static bool
+loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst,
+                                           const char *funcName) {
+    struct loader_icd_term *icd_term;
+    icd_term = inst->icd_terms;
+    while (NULL != icd_term) {
+        if (icd_term->scanned_icd->interface_version >=
+            MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
+            icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance,
+                                                             funcName))
+            // this icd supports funcName
+            return true;
+        icd_term = icd_term->next;
+    }
+
+    return false;
+}
+
+static bool
+loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst,
+                                                 const char *funcName) {
+    struct loader_layer_properties *layer_prop_list =
+        inst->activated_layer_list.list;
+    for (uint32_t layer = 0; layer < inst->activated_layer_list.count; ++layer) {
+        // If this layer supports the vk_layerGetPhysicalDeviceProcAddr, then call
+        // it and see if it returns a valid pointer for this function name.
+        if (layer_prop_list[layer].interface_version > 1) {
+            const struct loader_layer_functions *const functions =
+                &(layer_prop_list[layer].functions);
+            if (NULL != functions->get_physical_device_proc_addr &&
+                NULL !=
+                    functions->get_physical_device_proc_addr((VkInstance)inst,
+                                                             funcName)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+
+static void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
+    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
+        loader_instance_heap_free(inst,
+                                  inst->phys_dev_ext_disp_hash[i].func_name);
+        loader_instance_heap_free(inst,
+                                  inst->phys_dev_ext_disp_hash[i].list.index);
+    }
+    memset(inst->phys_dev_ext_disp_hash, 0,
+           sizeof(inst->phys_dev_ext_disp_hash));
+}
+
+static bool loader_add_phys_dev_ext_table(struct loader_instance *inst,
+                                          uint32_t *ptr_idx,
+                                          const char *funcName) {
+    uint32_t i;
+    uint32_t idx = *ptr_idx;
+    struct loader_dispatch_hash_list *list =
+        &inst->phys_dev_ext_disp_hash[idx].list;
+
+    if (!inst->phys_dev_ext_disp_hash[idx].func_name) {
+        // no entry here at this idx, so use it
+        assert(list->capacity == 0);
+        inst->phys_dev_ext_disp_hash[idx].func_name =
+            (char *)loader_instance_heap_alloc(
+                inst, strlen(funcName) + 1,
+                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+        if (inst->phys_dev_ext_disp_hash[idx].func_name == NULL) {
+            loader_log(
+                inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                "loader_add_phys_dev_ext_table() can't allocate memory for "
+                "func_name");
+            return false;
+        }
+        strncpy(inst->phys_dev_ext_disp_hash[idx].func_name, funcName,
+                strlen(funcName) + 1);
+        return true;
+    }
+
+    // check for enough capacity
+    if (list->capacity == 0) {
+        list->index =
+            loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)),
+                                       VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+        if (list->index == NULL) {
+            loader_log(
+                inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                "loader_add_phys_dev_ext_table() can't allocate list memory");
+            return false;
+        }
+        list->capacity = 8 * sizeof(*(list->index));
+    } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
+        list->index = loader_instance_heap_realloc(
+            inst, list->index, list->capacity, list->capacity * 2,
+            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+        if (list->index == NULL) {
+            loader_log(
+                inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                "loader_add_phys_dev_ext_table() can't reallocate list memory");
+            return false;
+        }
+        list->capacity *= 2;
+    }
+
+    // find an unused index in the hash table and use it
+    i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
+    do {
+        if (!inst->phys_dev_ext_disp_hash[i].func_name) {
+            assert(inst->phys_dev_ext_disp_hash[i].list.capacity == 0);
+            inst->phys_dev_ext_disp_hash[i].func_name =
+                (char *)loader_instance_heap_alloc(
+                    inst, strlen(funcName) + 1,
+                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+            if (inst->phys_dev_ext_disp_hash[i].func_name == NULL) {
+                loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                           "loader_add_dev_ext_table() can't rallocate "
+                           "func_name memory");
+                return false;
+            }
+            strncpy(inst->phys_dev_ext_disp_hash[i].func_name, funcName,
+                    strlen(funcName) + 1);
+            list->index[list->count] = i;
+            list->count++;
+            *ptr_idx = i;
+            return true;
+        }
+        i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
+    } while (i != idx);
+
+    loader_log(
+        inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+        "loader_add_phys_dev_ext_table() couldn't insert into hash table; is "
+        "it full?");
+    return false;
+}
+
+static bool loader_name_in_phys_dev_ext_table(struct loader_instance* inst,
+    uint32_t *idx, const char *funcName) {
+    uint32_t alt_idx;
+    if (inst->phys_dev_ext_disp_hash[*idx].func_name &&
+        !strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName))
+        return true;
+
+    // funcName wasn't at the primary spot in the hash table
+    // search the list of secondary locations (shallow search, not deep search)
+    for (uint32_t i = 0; i < inst->phys_dev_ext_disp_hash[*idx].list.count;
+         i++) {
+        alt_idx = inst->phys_dev_ext_disp_hash[*idx].list.index[i];
+        if (!strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName)) {
+            *idx = alt_idx;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// This function returns a generic trampoline and/or terminator function
+// address for any unknown physical device extension commands.  A hash
+// table is used to keep a list of unknown entry points and their
+// mapping to the physical device extension dispatch table (struct
+// loader_phys_dev_ext_dispatch_table).
+// For a given entry point string (funcName), if an existing mapping is
+// found, then the trampoline address for that mapping is returned in
+// tramp_addr (if it is not NULL) and the terminator address for that
+// mapping is returned in term_addr (if it is not NULL). Otherwise,
+// this unknown entry point has not been seen yet.
+// If it has not been seen before, and perform_checking is 'true',
+// check if a layer or and ICD supports it.  If so then a new entry in
+// the hash table is initialized and the trampoline and/or terminator
+// addresses are returned.
+// Null is returned if the hash table is full or if no discovered layer or
+// ICD returns a non-NULL GetProcAddr for it.
+bool loader_phys_dev_ext_gpa(struct loader_instance *inst, const char *funcName,
+                             bool perform_checking, void **tramp_addr,
+                             void **term_addr) {
+    uint32_t idx;
+    uint32_t seed = 0;
+    bool success = false;
+
+    if (inst == NULL) {
+        goto out;
+    }
+
+    if (NULL != tramp_addr) {
+        *tramp_addr = NULL;
+    }
+    if (NULL != term_addr) {
+        *term_addr = NULL;
+    }
+
+    // We should always check to see if any ICD supports it.
+    if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
+        // If we're not checking layers, or we are and it's not in a layer, just
+        // return
+        if (!perform_checking ||
+            !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
+            goto out;
+        }
+    }
+
+    idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
+    if (perform_checking &&
+        !loader_name_in_phys_dev_ext_table(inst, &idx, funcName)) {
+        uint32_t i;
+        bool added = false;
+
+        // Only need to add first one to get index in Instance.  Others will use
+        // the same index.
+        if (!added && loader_add_phys_dev_ext_table(inst, &idx, funcName)) {
+            added = true;
+        }
+
+        // Setup the ICD function pointers
+        struct loader_icd_term *icd_term = inst->icd_terms;
+        while (NULL != icd_term) {
+            if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <=
+                    icd_term->scanned_icd->interface_version &&
+                NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
+                icd_term->phys_dev_ext[idx] =
+                    (PFN_PhysDevExt)
+                        icd_term->scanned_icd->GetPhysicalDeviceProcAddr(
+                            icd_term->instance, funcName);
+
+                // Make sure we set the instance dispatch to point to the
+                // loader's terminator now since we can at least handle it
+                // in one ICD.
+                inst->disp->phys_dev_ext[idx] =
+                    loader_get_phys_dev_ext_termin(idx);
+            } else {
+                icd_term->phys_dev_ext[idx] = NULL;
+            }
+
+            icd_term = icd_term->next;
+        }
+
+        // Now, search for the first layer attached and query using it to get
+        // the first entry point.
+        for (i = 0; i < inst->activated_layer_list.count; i++) {
+            struct loader_layer_properties *layer_prop =
+                &inst->activated_layer_list.list[i];
+            if (layer_prop->interface_version > 1 &&
+                NULL != layer_prop->functions.get_physical_device_proc_addr) {
+                inst->disp->phys_dev_ext[idx] =
+                    (PFN_PhysDevExt)
+                        layer_prop->functions.get_physical_device_proc_addr(
+                            (VkInstance)inst, funcName);
+                if (NULL != inst->disp->phys_dev_ext[idx]) {
+                    break;
+                }
+            }
+        }
+    }
+
+    if (NULL != tramp_addr) {
+        *tramp_addr = loader_get_phys_dev_ext_tramp(idx);
+    }
+
+    if (NULL != term_addr) {
+        *term_addr = loader_get_phys_dev_ext_termin(idx);
+    }
+
+    success = true;
+
+out:
+    return success;
+}
+
 struct loader_instance *loader_get_instance(const VkInstance instance) {
     /* look up the loader_instance in our list by comparing dispatch tables, as
      * there is no guarantee the instance is still a loader_instance* after any
@@ -3803,10 +4268,10 @@
      */
     const VkLayerInstanceDispatchTable *disp;
     struct loader_instance *ptr_instance = NULL;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     for (struct loader_instance *inst = loader.instances; inst;
          inst = inst->next) {
-        if (inst->disp == disp) {
+        if (&inst->disp->layer_inst_disp == disp) {
             ptr_instance = inst;
             break;
         }
@@ -3987,6 +4452,40 @@
     return err;
 }
 
+// Determine the layer interface version to use.
+bool loader_get_layer_interface_version(
+    PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
+    VkNegotiateLayerInterface *interface_struct) {
+
+    memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
+
+    // Base assumption is that all layers are version 1 at least.
+    interface_struct->loaderLayerInterfaceVersion = 1;
+
+    if (fp_negotiate_layer_version != NULL) {
+        // Layer supports the negotiation API, so call it with the loader's
+        // latest version supported
+        interface_struct->loaderLayerInterfaceVersion =
+            CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+        VkResult result = fp_negotiate_layer_version(interface_struct);
+
+        if (result != VK_SUCCESS) {
+            // Layer no longer supports the loader's latest interface version so
+            // fail loading the Layer
+            return false;
+        }
+    }
+
+    if (interface_struct->loaderLayerInterfaceVersion <
+        MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
+        // Loader no longer supports the layer's latest interface version so
+        // fail loading the layer
+        return false;
+    }
+
+    return true;
+}
+
 /*
  * Given the list of layers to activate in the loader_instance
  * structure. This function will add a VkLayerInstanceCreateInfo
@@ -4015,8 +4514,10 @@
     VkInstanceCreateInfo loader_create_info;
     VkResult res;
 
-    PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
-    PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
+    PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_internal;
+    PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_internal;
+    PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_internal;
+    PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_internal;
 
     memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
 
@@ -4037,42 +4538,113 @@
             return VK_ERROR_OUT_OF_HOST_MEMORY;
         }
 
-        /* Create instance chain of enabled layers */
+        // Create instance chain of enabled layers
         for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
             struct loader_layer_properties *layer_prop =
                 &inst->activated_layer_list.list[i];
             loader_platform_dl_handle lib_handle;
 
             lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
-            if (!lib_handle)
+            if (!lib_handle) {
                 continue;
-            if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
-                NULL) {
-                if (strlen(layer_prop->functions.str_gipa) == 0) {
-                    fpGIPA = (PFN_vkGetInstanceProcAddr)
-                        loader_platform_get_proc_address(
-                            lib_handle, "vkGetInstanceProcAddr");
-                    layer_prop->functions.get_instance_proc_addr = fpGIPA;
-                } else
-                    fpGIPA = (PFN_vkGetInstanceProcAddr)
-                        loader_platform_get_proc_address(
-                            lib_handle, layer_prop->functions.str_gipa);
-                if (!fpGIPA) {
-                    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
-                               "loader_create_instance_chain: Failed to find "
-                               "\'vkGetInstanceProcAddr\' in layer %s",
-                               layer_prop->lib_name);
-                    continue;
+            }
+
+            if (NULL == layer_prop->functions.negotiate_layer_interface) {
+                PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface =
+                    NULL;
+                bool functions_in_interface = false;
+                if (strlen(layer_prop->functions.str_negotiate_interface) ==
+                        0) {
+                    negotiate_interface =
+                        (PFN_vkNegotiateLoaderLayerInterfaceVersion)
+                            loader_platform_get_proc_address(
+                                lib_handle,
+                                "vkNegotiateLoaderLayerInterfaceVersion");
+                } else {
+                    negotiate_interface =
+                        (PFN_vkNegotiateLoaderLayerInterfaceVersion)
+                            loader_platform_get_proc_address(
+                                lib_handle,
+                                layer_prop->functions.str_negotiate_interface);
+                }
+
+                // If we can negotiate an interface version, then we can also
+                // get everything we need from the one function call, so try
+                // that first, and see if we can get all the function pointers
+                // necessary from that one call.
+                if (NULL != negotiate_interface) {
+                    layer_prop->functions.negotiate_layer_interface =
+                        negotiate_interface;
+
+                    VkNegotiateLayerInterface interface_struct;
+
+                    if (loader_get_layer_interface_version(negotiate_interface,
+                                                           &interface_struct)) {
+
+                        // Go ahead and set the properites version to the
+                        // correct value.
+                        layer_prop->interface_version =
+                            interface_struct.loaderLayerInterfaceVersion;
+
+                        // If the interface is 2 or newer, we have access to the
+                        // new GetPhysicalDeviceProcAddr function, so grab it,
+                        // and the other necessary functions, from the
+                        // structure.
+                        if (interface_struct.loaderLayerInterfaceVersion > 1) {
+                            cur_gipa = interface_struct.pfnGetInstanceProcAddr;
+                            cur_gpdpa =
+                                interface_struct.pfnGetPhysicalDeviceProcAddr;
+                            if (cur_gipa != NULL) {
+                                // We've set the functions, so make sure we
+                                // don't do the unnecessary calls later.
+                                functions_in_interface = true;
+                            }
+                        }
+                    }
+                }
+
+                if (!functions_in_interface) {
+                    if ((cur_gipa =
+                             layer_prop->functions.get_instance_proc_addr) ==
+                        NULL) {
+                        if (strlen(layer_prop->functions.str_gipa) == 0) {
+                            cur_gipa = (PFN_vkGetInstanceProcAddr)
+                                loader_platform_get_proc_address(
+                                    lib_handle, "vkGetInstanceProcAddr");
+                            layer_prop->functions.get_instance_proc_addr =
+                                cur_gipa;
+                        } else {
+                            cur_gipa = (PFN_vkGetInstanceProcAddr)
+                                loader_platform_get_proc_address(
+                                    lib_handle, layer_prop->functions.str_gipa);
+                        }
+
+                        if (NULL == cur_gipa) {
+                            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                                       "loader_create_instance_chain: Failed to"
+                                       " find \'vkGetInstanceProcAddr\' in "
+                                       "layer %s",
+                                       layer_prop->lib_name);
+                            continue;
+                        }
+                    }
                 }
             }
 
             layer_instance_link_info[activated_layers].pNext =
                 chain_info.u.pLayerInfo;
             layer_instance_link_info[activated_layers]
-                .pfnNextGetInstanceProcAddr = nextGIPA;
+                .pfnNextGetInstanceProcAddr = next_gipa;
+            layer_instance_link_info[activated_layers]
+                .pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
+            next_gipa = cur_gipa;
+            if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
+                layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
+                next_gpdpa = cur_gpdpa;
+            }
+
             chain_info.u.pLayerInfo =
                 &layer_instance_link_info[activated_layers];
-            nextGIPA = fpGIPA;
 
             loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
                        "Insert instance layer %s (%s)",
@@ -4083,7 +4655,7 @@
     }
 
     PFN_vkCreateInstance fpCreateInstance =
-        (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
+        (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
     if (fpCreateInstance) {
         VkLayerInstanceCreateInfo create_info_disp;
 
@@ -4104,11 +4676,9 @@
         res = VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    if (res != VK_SUCCESS) {
-        // TODO: Need to clean up here
-    } else {
-        loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
-                                                 *created_instance);
+    if (res == VK_SUCCESS) {
+        loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp,
+                                                 next_gipa, *created_instance);
         inst->instance = *created_instance;
     }
 
@@ -4119,7 +4689,8 @@
                                                VkInstance created_inst) {
 
     loader_init_instance_extension_dispatch_table(
-        inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
+        &inst->disp->layer_inst_disp,
+        inst->disp->layer_inst_disp.GetInstanceProcAddr, created_inst);
 }
 
 VkResult
@@ -4152,57 +4723,113 @@
         chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
         chain_info.function = VK_LAYER_LINK_INFO;
         chain_info.u.pLayerInfo = NULL;
-        chain_info.pNext = pCreateInfo->pNext;
+        chain_info.pNext = loader_create_info.pNext;
         loader_create_info.pNext = &chain_info;
 
-        /* Create instance chain of enabled layers */
+        // Create instance chain of enabled layers
         for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
             struct loader_layer_properties *layer_prop =
                 &dev->activated_layer_list.list[i];
             loader_platform_dl_handle lib_handle;
+            bool functions_in_interface = false;
 
             lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
-            if (!lib_handle)
+            if (!lib_handle) {
                 continue;
-            if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
-                NULL) {
-                if (strlen(layer_prop->functions.str_gipa) == 0) {
-                    fpGIPA = (PFN_vkGetInstanceProcAddr)
-                        loader_platform_get_proc_address(
-                            lib_handle, "vkGetInstanceProcAddr");
-                    layer_prop->functions.get_instance_proc_addr = fpGIPA;
-                } else
-                    fpGIPA = (PFN_vkGetInstanceProcAddr)
-                        loader_platform_get_proc_address(
-                            lib_handle, layer_prop->functions.str_gipa);
-                if (!fpGIPA) {
-                    loader_log(
-                        inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
-                        "loader_create_device_chain: Failed to find "
-                        "\'vkGetInstanceProcAddr\' in layer %s.  Skipping"
-                        " layer.",
-                        layer_prop->lib_name);
-                    continue;
-                }
             }
-            if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
-                if (strlen(layer_prop->functions.str_gdpa) == 0) {
-                    fpGDPA = (PFN_vkGetDeviceProcAddr)
-                        loader_platform_get_proc_address(lib_handle,
-                                                         "vkGetDeviceProcAddr");
-                    layer_prop->functions.get_device_proc_addr = fpGDPA;
-                } else
-                    fpGDPA = (PFN_vkGetDeviceProcAddr)
-                        loader_platform_get_proc_address(
-                            lib_handle, layer_prop->functions.str_gdpa);
-                if (!fpGDPA) {
-                    loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
-                               "Failed to find vkGetDeviceProcAddr in layer %s",
-                               layer_prop->lib_name);
-                    continue;
+
+            // If we can negotiate an interface version, then we can also
+            // get everything we need from the one function call, so try
+            // that first, and see if we can get all the function pointers
+            // necessary from that one call.
+            if (NULL == layer_prop->functions.negotiate_layer_interface) {
+                PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface =
+                    NULL;
+                if (strlen(layer_prop->functions.str_negotiate_interface) ==
+                        0) {
+                    negotiate_interface =
+                        (PFN_vkNegotiateLoaderLayerInterfaceVersion)
+                            loader_platform_get_proc_address(
+                                lib_handle,
+                                "vkNegotiateLoaderLayerInterfaceVersion");
+                } else {
+                    negotiate_interface =
+                        (PFN_vkNegotiateLoaderLayerInterfaceVersion)
+                            loader_platform_get_proc_address(
+                                lib_handle,
+                                layer_prop->functions.str_negotiate_interface);
+                }
+
+                if (NULL != negotiate_interface) {
+                    layer_prop->functions.negotiate_layer_interface =
+                        negotiate_interface;
+
+                    VkNegotiateLayerInterface interface_struct;
+
+                    if (loader_get_layer_interface_version(negotiate_interface,
+                        &interface_struct)) {
+
+                        // Go ahead and set the properites version to the
+                        // correct value.
+                        layer_prop->interface_version =
+                            interface_struct.loaderLayerInterfaceVersion;
+
+                        // If the interface is 2 or newer, we have access to the
+                        // new GetPhysicalDeviceProcAddr function, so grab it,
+                        // and the other necessary functions, from the structure.
+                        if (interface_struct.loaderLayerInterfaceVersion > 1) {
+                            fpGIPA = interface_struct.pfnGetInstanceProcAddr;
+                            fpGDPA = interface_struct.pfnGetDeviceProcAddr;
+                            if (fpGIPA != NULL && fpGDPA) {
+                                // We've set the functions, so make sure we
+                                // don't do the unnecessary calls later.
+                                functions_in_interface = true;
+                            }
+                        }
+                    }
                 }
             }
 
+            if (!functions_in_interface) {
+                if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
+                    NULL) {
+                    if (strlen(layer_prop->functions.str_gipa) == 0) {
+                        fpGIPA = (PFN_vkGetInstanceProcAddr)
+                            loader_platform_get_proc_address(
+                                lib_handle, "vkGetInstanceProcAddr");
+                        layer_prop->functions.get_instance_proc_addr = fpGIPA;
+                    } else
+                        fpGIPA = (PFN_vkGetInstanceProcAddr)
+                        loader_platform_get_proc_address(
+                            lib_handle, layer_prop->functions.str_gipa);
+                    if (!fpGIPA) {
+                        loader_log(
+                            inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                            "loader_create_device_chain: Failed to find "
+                            "\'vkGetInstanceProcAddr\' in layer %s.  Skipping"
+                            " layer.",
+                            layer_prop->lib_name);
+                        continue;
+                    }
+                }
+                if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
+                    if (strlen(layer_prop->functions.str_gdpa) == 0) {
+                        fpGDPA = (PFN_vkGetDeviceProcAddr)
+                            loader_platform_get_proc_address(lib_handle,
+                                "vkGetDeviceProcAddr");
+                        layer_prop->functions.get_device_proc_addr = fpGDPA;
+                    } else
+                        fpGDPA = (PFN_vkGetDeviceProcAddr)
+                        loader_platform_get_proc_address(
+                            lib_handle, layer_prop->functions.str_gdpa);
+                    if (!fpGDPA) {
+                        loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
+                            "Failed to find vkGetDeviceProcAddr in layer %s",
+                            layer_prop->lib_name);
+                        continue;
+                    }
+                }
+            }
             layer_device_link_info[activated_layers].pNext =
                 chain_info.u.pLayerInfo;
             layer_device_link_info[activated_layers]
@@ -4617,7 +5244,7 @@
     loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
     loader_destroy_generic_list(
         ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
-    if (ptr_instance->phys_devs_term) {
+    if (NULL != ptr_instance->phys_devs_term) {
         for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
             loader_instance_heap_free(ptr_instance,
                                       ptr_instance->phys_devs_term[i]);
@@ -4625,6 +5252,7 @@
         loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
     }
     loader_free_dev_ext_table(ptr_instance);
+    loader_free_phys_dev_ext_table(ptr_instance);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
@@ -4780,8 +5408,8 @@
     }
     memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
 
-    res = inst->disp->EnumeratePhysicalDevices(instance, &total_count,
-                                               local_phys_devs);
+    res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(
+        instance, &total_count, local_phys_devs);
     if (VK_SUCCESS != res) {
         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                    "setupLoaderTrampPhysDevs:  Failed during dispatch call "
diff --git a/loader/loader.h b/loader/loader.h
index 45dc223..019125f 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -52,6 +52,13 @@
 #define VK_MINOR(version) ((version >> 12) & 0x3ff)
 #define VK_PATCH(version) (version & 0xfff)
 
+// This is defined in vk_layer.h, but if there's problems we need to create the define
+// here.
+#ifndef MAX_NUM_UNKNOWN_EXTS
+#define MAX_NUM_UNKNOWN_EXTS 250
+#endif
+
+
 enum layer_type {
     VK_LAYER_TYPE_INSTANCE_EXPLICIT = 0x1,
     VK_LAYER_TYPE_INSTANCE_IMPLICIT = 0x2,
@@ -81,6 +88,11 @@
     "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain",
      "VK_LAYER_GOOGLE_unique_objects"};
 
+struct VkStructureHeader {
+    VkStructureType sType;
+    const void* pNext;
+};
+
 // form of all dynamic lists/arrays
 // only the list element should be changed
 struct loader_generic_list {
@@ -115,13 +127,17 @@
 struct loader_layer_functions {
     char str_gipa[MAX_STRING_SIZE];
     char str_gdpa[MAX_STRING_SIZE];
+    char str_negotiate_interface[MAX_STRING_SIZE];
+    PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_layer_interface;
     PFN_vkGetInstanceProcAddr get_instance_proc_addr;
     PFN_vkGetDeviceProcAddr get_device_proc_addr;
+    PFN_GetPhysicalDeviceProcAddr get_physical_device_proc_addr;
 };
 
 struct loader_layer_properties {
     VkLayerProperties info;
     enum layer_type type;
+    uint32_t interface_version; // PFN_vkNegotiateLoaderLayerInterfaceVersion
     char lib_name[MAX_STRING_SIZE];
     loader_platform_dl_handle lib_handle;
     struct loader_layer_functions functions;
@@ -143,7 +159,7 @@
     uint32_t *index; // index into the dev_ext dispatch table
 };
 
-#define MAX_NUM_DEV_EXTS 250
+
 // loader_dispatch_hash_entry and loader_dev_ext_dispatch_table.dev_ext have
 // one to one correspondence; one loader_dispatch_hash_entry for one dev_ext
 // dispatch entry.
@@ -155,7 +171,7 @@
 
 typedef void(VKAPI_PTR *PFN_vkDevExt)(VkDevice device);
 struct loader_dev_ext_dispatch_table {
-    PFN_vkDevExt dev_ext[MAX_NUM_DEV_EXTS];
+    PFN_vkDevExt dev_ext[MAX_NUM_UNKNOWN_EXTS];
 };
 
 struct loader_dev_dispatch_table {
@@ -199,19 +215,13 @@
     PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
     PFN_vkGetPhysicalDeviceSparseImageFormatProperties
         GetPhysicalDeviceSparseImageFormatProperties;
-    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
-    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
-    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
-    PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
-    PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
+    // WSI extensions
     PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
         GetPhysicalDeviceSurfaceCapabilitiesKHR;
     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
         GetPhysicalDeviceSurfacePresentModesKHR;
-    PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV
-        GetPhysicalDeviceExternalImageFormatPropertiesNV;
 #ifdef VK_USE_PLATFORM_WIN32_KHR
     PFN_vkCreateWin32SurfaceKHR CreateWin32SurfaceKHR;
     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR
@@ -249,12 +259,55 @@
     PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR;
     PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
     PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
+    PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;
+
+    // KHR_get_physical_device_properties2
+    PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR;
+    PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;
+    PFN_vkGetPhysicalDeviceFormatProperties2KHR
+        GetPhysicalDeviceFormatProperties2KHR;
+    PFN_vkGetPhysicalDeviceImageFormatProperties2KHR
+        GetPhysicalDeviceImageFormatProperties2KHR;
+    PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR
+        GetPhysicalDeviceQueueFamilyProperties2KHR;
+    PFN_vkGetPhysicalDeviceMemoryProperties2KHR
+        GetPhysicalDeviceMemoryProperties2KHR;
+    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR
+        GetPhysicalDeviceSparseImageFormatProperties2KHR;
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // EXT_acquire_xlib_display
+    PFN_vkAcquireXlibDisplayEXT AcquireXlibDisplayEXT;
+    PFN_vkGetRandROutputDisplayEXT GetRandROutputDisplayEXT;
+#endif
+
+    // EXT_debug_report
+    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
+    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+
+    // EXT_debug_marker (items needing a trampoline/terminator)
+    PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
+    PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
+
+    // EXT_direct_mode_display
+    PFN_vkReleaseDisplayEXT ReleaseDisplayEXT;
+
+    // EXT_display_surface_counter
+    PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT
+        GetPhysicalDeviceSurfaceCapabilities2EXT;
+
+    // NV_external_memory_capabilities
+    PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV
+        GetPhysicalDeviceExternalImageFormatPropertiesNV;
 
     // NVX_device_generated_commands
     PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX
         GetPhysicalDeviceGeneratedCommandsPropertiesNVX;
 
     struct loader_icd_term *next;
+
+    PFN_PhysDevExt  phys_dev_ext[MAX_NUM_UNKNOWN_EXTS];
 };
 
 // per ICD library structure
@@ -266,15 +319,26 @@
 
 union loader_instance_extension_enables {
     struct {
+        uint8_t khr_get_physical_device_properties2 : 1;
+        uint8_t ext_acquire_xlib_display : 1;
         uint8_t ext_debug_report : 1;
+        uint8_t ext_direct_mode_display : 1;
+        uint8_t ext_display_surface_counter : 1;
         uint8_t nv_external_memory_capabilities : 1;
     };
     uint64_t padding[4];
 };
 
+struct loader_instance_dispatch_table {
+    VkLayerInstanceDispatchTable layer_inst_disp; // must be first entry in structure
+
+    // Physical device functions unknown to the loader
+    PFN_PhysDevExt  phys_dev_ext[MAX_NUM_UNKNOWN_EXTS];
+};
+
 // per instance structure
 struct loader_instance {
-    VkLayerInstanceDispatchTable *disp; // must be first entry in structure
+    struct loader_instance_dispatch_table *disp; // must be first entry in structure
 
     uint32_t total_gpu_count;
     uint32_t phys_dev_count_term;
@@ -288,7 +352,8 @@
     struct loader_icd_term *icd_terms;
     struct loader_icd_tramp_list icd_tramp_list;
 
-    struct loader_dispatch_hash_entry disp_hash[MAX_NUM_DEV_EXTS];
+    struct loader_dispatch_hash_entry dev_ext_disp_hash[MAX_NUM_UNKNOWN_EXTS];
+    struct loader_dispatch_hash_entry phys_dev_ext_disp_hash[MAX_NUM_UNKNOWN_EXTS];
 
     struct loader_msg_callback_map_entry *icd_msg_callback_map;
 
@@ -344,14 +409,14 @@
 /* per enumerated PhysicalDevice structure, used to wrap in trampoline code and
    also same structure used to wrap in terminator code */
 struct loader_physical_device_tramp {
-    VkLayerInstanceDispatchTable *disp; // must be first entry in structure
+    struct loader_instance_dispatch_table *disp; // must be first entry in structure
     struct loader_instance *this_instance;
     VkPhysicalDevice phys_dev; // object from layers/loader terminator
 };
 
 /* per enumerated PhysicalDevice structure, used to wrap in terminator code */
 struct loader_physical_device_term {
-    VkLayerInstanceDispatchTable *disp; // must be first entry in structure
+    struct loader_instance_dispatch_table *disp; // must be first entry in structure
     struct loader_icd_term *this_icd_term;
     uint8_t icd_index;
     VkPhysicalDevice phys_dev; // object from ICD
@@ -367,6 +432,7 @@
     uint32_t api_version;
     uint32_t interface_version;
     PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;
     PFN_vkCreateInstance CreateInstance;
     PFN_vkEnumerateInstanceExtensionProperties
         EnumerateInstanceExtensionProperties;
@@ -397,10 +463,15 @@
 }
 
 static inline VkLayerInstanceDispatchTable *
-loader_get_instance_dispatch(const void *obj) {
+loader_get_instance_layer_dispatch(const void *obj) {
     return *((VkLayerInstanceDispatchTable **)obj);
 }
 
+static inline struct loader_instance_dispatch_table *
+loader_get_instance_dispatch(const void *obj) {
+    return *((struct loader_instance_dispatch_table **)obj);
+}
+
 static inline void loader_init_dispatch(void *obj, const void *data) {
 #ifdef DEBUG
     assert(valid_loader_magic_value(obj) &&
@@ -537,7 +608,10 @@
                                   struct loader_device *dev);
 void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName);
 void *loader_get_dev_ext_trampoline(uint32_t index);
-void loader_override_terminating_device_proc(struct loader_device *dev);
+bool loader_phys_dev_ext_gpa(struct loader_instance *inst, const char *funcName,
+                             bool perform_checking, void **tramp_addr, void **term_addr);
+void *loader_get_phys_dev_ext_tramp(uint32_t index);
+void *loader_get_phys_dev_ext_termin(uint32_t index);
 struct loader_instance *loader_get_instance(const VkInstance instance);
 void loader_deactivate_layers(const struct loader_instance *instance,
                               struct loader_device *device,
@@ -583,6 +657,7 @@
                            const VkAllocationCallbacks *pAllocator,
                            const struct loader_instance *inst,
                            struct loader_device *dev);
+
 VkResult loader_validate_device_extensions(
     struct loader_physical_device_tramp *phys_dev,
     const struct loader_layer_list *activated_device_layers,
diff --git a/loader/loader.rc b/loader/loader.rc
index 0422699..177de20 100755
--- a/loader/loader.rc
+++ b/loader/loader.rc
@@ -1,7 +1,7 @@
 //
-// Copyright (c) 2014-2016 The Khronos Group Inc.
-// Copyright (c) 2014-2016 Valve Corporation
-// Copyright (c) 2014-2016 LunarG, Inc.
+// Copyright (c) 2014-2017 The Khronos Group Inc.
+// Copyright (c) 2014-2017 Valve Corporation
+// Copyright (c) 2014-2017 LunarG, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@
         BEGIN
             VALUE "FileDescription", VER_FILE_DESCRIPTION_STR
             VALUE "FileVersion", VER_FILE_VERSION_STR
-            VALUE "LegalCopyright", "Copyright (C) 2015-2016"
+            VALUE "LegalCopyright", "Copyright (C) 2015-2017"
             VALUE "ProductName", "Vulkan Runtime"
             VALUE "ProductVersion", VER_FILE_VERSION_STR
         END
diff --git a/loader/phys_dev_ext.c b/loader/phys_dev_ext.c
new file mode 100644
index 0000000..9083025
--- /dev/null
+++ b/loader/phys_dev_ext.c
@@ -0,0 +1,828 @@
+/*
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Valve Corporation
+ * Copyright (c) 2016 LunarG, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Mark Young <marky@lunarg.com>
+ *
+ */
+
+// This code is used to enable generic instance extensions which use a physical device
+// as the first parameter.  If the extension is already known by the loader, it will
+// not use this code, but instead use the more direct route.  However, if it is
+// unknown to the loader, it will use this code.  Technically, this is not trampoline
+// code since we don't want to optimize it out.
+
+#include "vk_loader_platform.h"
+#include "loader.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC optimize(3) // force gcc to use tail-calls
+#endif
+
+// Trampoline function macro for unknown physical device extension command.
+#define PhysDevExtTramp(num)                                                   \
+VKAPI_ATTR void VKAPI_CALL vkPhysDevExtTramp##num(                             \
+        VkPhysicalDevice physical_device) {                                    \
+        const struct loader_instance_dispatch_table *disp;                     \
+        disp = loader_get_instance_dispatch(physical_device);                  \
+        disp->phys_dev_ext[num](                                               \
+            loader_unwrap_physical_device(physical_device));                   \
+    }
+
+// Terminator function macro for unknown physical device extension command.
+#define PhysDevExtTermin(num)                                                  \
+VKAPI_ATTR void VKAPI_CALL vkPhysDevExtTermin##num(                            \
+        VkPhysicalDevice physical_device) {                                    \
+        struct loader_physical_device_term *phys_dev_term =                    \
+            (struct loader_physical_device_term *)physical_device;             \
+        struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;       \
+        struct loader_instance *inst =                                         \
+            (struct loader_instance *)icd_term->this_instance;                 \
+        if (NULL == icd_term->phys_dev_ext[num]) {                             \
+            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,                 \
+                       "Extension %s not supported for this physical device",  \
+                       inst->phys_dev_ext_disp_hash[num].func_name);           \
+        }                                                                      \
+        icd_term->phys_dev_ext[num](phys_dev_term->phys_dev);                  \
+    }
+
+// Instantiations of the trampoline and terminator
+PhysDevExtTramp(0)   PhysDevExtTermin(0)
+PhysDevExtTramp(1)   PhysDevExtTermin(1)
+PhysDevExtTramp(2)   PhysDevExtTermin(2)
+PhysDevExtTramp(3)   PhysDevExtTermin(3)
+PhysDevExtTramp(4)   PhysDevExtTermin(4)
+PhysDevExtTramp(5)   PhysDevExtTermin(5)
+PhysDevExtTramp(6)   PhysDevExtTermin(6)
+PhysDevExtTramp(7)   PhysDevExtTermin(7)
+PhysDevExtTramp(8)   PhysDevExtTermin(8)
+PhysDevExtTramp(9)   PhysDevExtTermin(9)
+PhysDevExtTramp(10)  PhysDevExtTermin(10)
+PhysDevExtTramp(11)  PhysDevExtTermin(11)
+PhysDevExtTramp(12)  PhysDevExtTermin(12)
+PhysDevExtTramp(13)  PhysDevExtTermin(13)
+PhysDevExtTramp(14)  PhysDevExtTermin(14)
+PhysDevExtTramp(15)  PhysDevExtTermin(15)
+PhysDevExtTramp(16)  PhysDevExtTermin(16)
+PhysDevExtTramp(17)  PhysDevExtTermin(17)
+PhysDevExtTramp(18)  PhysDevExtTermin(18)
+PhysDevExtTramp(19)  PhysDevExtTermin(19)
+PhysDevExtTramp(20)  PhysDevExtTermin(20)
+PhysDevExtTramp(21)  PhysDevExtTermin(21)
+PhysDevExtTramp(22)  PhysDevExtTermin(22)
+PhysDevExtTramp(23)  PhysDevExtTermin(23)
+PhysDevExtTramp(24)  PhysDevExtTermin(24)
+PhysDevExtTramp(25)  PhysDevExtTermin(25)
+PhysDevExtTramp(26)  PhysDevExtTermin(26)
+PhysDevExtTramp(27)  PhysDevExtTermin(27)
+PhysDevExtTramp(28)  PhysDevExtTermin(28)
+PhysDevExtTramp(29)  PhysDevExtTermin(29)
+PhysDevExtTramp(30)  PhysDevExtTermin(30)
+PhysDevExtTramp(31)  PhysDevExtTermin(31)
+PhysDevExtTramp(32)  PhysDevExtTermin(32)
+PhysDevExtTramp(33)  PhysDevExtTermin(33)
+PhysDevExtTramp(34)  PhysDevExtTermin(34)
+PhysDevExtTramp(35)  PhysDevExtTermin(35)
+PhysDevExtTramp(36)  PhysDevExtTermin(36)
+PhysDevExtTramp(37)  PhysDevExtTermin(37)
+PhysDevExtTramp(38)  PhysDevExtTermin(38)
+PhysDevExtTramp(39)  PhysDevExtTermin(39)
+PhysDevExtTramp(40)  PhysDevExtTermin(40)
+PhysDevExtTramp(41)  PhysDevExtTermin(41)
+PhysDevExtTramp(42)  PhysDevExtTermin(42)
+PhysDevExtTramp(43)  PhysDevExtTermin(43)
+PhysDevExtTramp(44)  PhysDevExtTermin(44)
+PhysDevExtTramp(45)  PhysDevExtTermin(45)
+PhysDevExtTramp(46)  PhysDevExtTermin(46)
+PhysDevExtTramp(47)  PhysDevExtTermin(47)
+PhysDevExtTramp(48)  PhysDevExtTermin(48)
+PhysDevExtTramp(49)  PhysDevExtTermin(49)
+PhysDevExtTramp(50)  PhysDevExtTermin(50)
+PhysDevExtTramp(51)  PhysDevExtTermin(51)
+PhysDevExtTramp(52)  PhysDevExtTermin(52)
+PhysDevExtTramp(53)  PhysDevExtTermin(53)
+PhysDevExtTramp(54)  PhysDevExtTermin(54)
+PhysDevExtTramp(55)  PhysDevExtTermin(55)
+PhysDevExtTramp(56)  PhysDevExtTermin(56)
+PhysDevExtTramp(57)  PhysDevExtTermin(57)
+PhysDevExtTramp(58)  PhysDevExtTermin(58)
+PhysDevExtTramp(59)  PhysDevExtTermin(59)
+PhysDevExtTramp(60)  PhysDevExtTermin(60)
+PhysDevExtTramp(61)  PhysDevExtTermin(61)
+PhysDevExtTramp(62)  PhysDevExtTermin(62)
+PhysDevExtTramp(63)  PhysDevExtTermin(63)
+PhysDevExtTramp(64)  PhysDevExtTermin(64)
+PhysDevExtTramp(65)  PhysDevExtTermin(65)
+PhysDevExtTramp(66)  PhysDevExtTermin(66)
+PhysDevExtTramp(67)  PhysDevExtTermin(67)
+PhysDevExtTramp(68)  PhysDevExtTermin(68)
+PhysDevExtTramp(69)  PhysDevExtTermin(69)
+PhysDevExtTramp(70)  PhysDevExtTermin(70)
+PhysDevExtTramp(71)  PhysDevExtTermin(71)
+PhysDevExtTramp(72)  PhysDevExtTermin(72)
+PhysDevExtTramp(73)  PhysDevExtTermin(73)
+PhysDevExtTramp(74)  PhysDevExtTermin(74)
+PhysDevExtTramp(75)  PhysDevExtTermin(75)
+PhysDevExtTramp(76)  PhysDevExtTermin(76)
+PhysDevExtTramp(77)  PhysDevExtTermin(77)
+PhysDevExtTramp(78)  PhysDevExtTermin(78)
+PhysDevExtTramp(79)  PhysDevExtTermin(79)
+PhysDevExtTramp(80)  PhysDevExtTermin(80)
+PhysDevExtTramp(81)  PhysDevExtTermin(81)
+PhysDevExtTramp(82)  PhysDevExtTermin(82)
+PhysDevExtTramp(83)  PhysDevExtTermin(83)
+PhysDevExtTramp(84)  PhysDevExtTermin(84)
+PhysDevExtTramp(85)  PhysDevExtTermin(85)
+PhysDevExtTramp(86)  PhysDevExtTermin(86)
+PhysDevExtTramp(87)  PhysDevExtTermin(87)
+PhysDevExtTramp(88)  PhysDevExtTermin(88)
+PhysDevExtTramp(89)  PhysDevExtTermin(89)
+PhysDevExtTramp(90)  PhysDevExtTermin(90)
+PhysDevExtTramp(91)  PhysDevExtTermin(91)
+PhysDevExtTramp(92)  PhysDevExtTermin(92)
+PhysDevExtTramp(93)  PhysDevExtTermin(93)
+PhysDevExtTramp(94)  PhysDevExtTermin(94)
+PhysDevExtTramp(95)  PhysDevExtTermin(95)
+PhysDevExtTramp(96)  PhysDevExtTermin(96)
+PhysDevExtTramp(97)  PhysDevExtTermin(97)
+PhysDevExtTramp(98)  PhysDevExtTermin(98)
+PhysDevExtTramp(99)  PhysDevExtTermin(99)
+PhysDevExtTramp(100) PhysDevExtTermin(100)
+PhysDevExtTramp(101) PhysDevExtTermin(101)
+PhysDevExtTramp(102) PhysDevExtTermin(102)
+PhysDevExtTramp(103) PhysDevExtTermin(103)
+PhysDevExtTramp(104) PhysDevExtTermin(104)
+PhysDevExtTramp(105) PhysDevExtTermin(105)
+PhysDevExtTramp(106) PhysDevExtTermin(106)
+PhysDevExtTramp(107) PhysDevExtTermin(107)
+PhysDevExtTramp(108) PhysDevExtTermin(108)
+PhysDevExtTramp(109) PhysDevExtTermin(109)
+PhysDevExtTramp(110) PhysDevExtTermin(110)
+PhysDevExtTramp(111) PhysDevExtTermin(111)
+PhysDevExtTramp(112) PhysDevExtTermin(112)
+PhysDevExtTramp(113) PhysDevExtTermin(113)
+PhysDevExtTramp(114) PhysDevExtTermin(114)
+PhysDevExtTramp(115) PhysDevExtTermin(115)
+PhysDevExtTramp(116) PhysDevExtTermin(116)
+PhysDevExtTramp(117) PhysDevExtTermin(117)
+PhysDevExtTramp(118) PhysDevExtTermin(118)
+PhysDevExtTramp(119) PhysDevExtTermin(119)
+PhysDevExtTramp(120) PhysDevExtTermin(120)
+PhysDevExtTramp(121) PhysDevExtTermin(121)
+PhysDevExtTramp(122) PhysDevExtTermin(122)
+PhysDevExtTramp(123) PhysDevExtTermin(123)
+PhysDevExtTramp(124) PhysDevExtTermin(124)
+PhysDevExtTramp(125) PhysDevExtTermin(125)
+PhysDevExtTramp(126) PhysDevExtTermin(126)
+PhysDevExtTramp(127) PhysDevExtTermin(127)
+PhysDevExtTramp(128) PhysDevExtTermin(128)
+PhysDevExtTramp(129) PhysDevExtTermin(129)
+PhysDevExtTramp(130) PhysDevExtTermin(130)
+PhysDevExtTramp(131) PhysDevExtTermin(131)
+PhysDevExtTramp(132) PhysDevExtTermin(132)
+PhysDevExtTramp(133) PhysDevExtTermin(133)
+PhysDevExtTramp(134) PhysDevExtTermin(134)
+PhysDevExtTramp(135) PhysDevExtTermin(135)
+PhysDevExtTramp(136) PhysDevExtTermin(136)
+PhysDevExtTramp(137) PhysDevExtTermin(137)
+PhysDevExtTramp(138) PhysDevExtTermin(138)
+PhysDevExtTramp(139) PhysDevExtTermin(139)
+PhysDevExtTramp(140) PhysDevExtTermin(140)
+PhysDevExtTramp(141) PhysDevExtTermin(141)
+PhysDevExtTramp(142) PhysDevExtTermin(142)
+PhysDevExtTramp(143) PhysDevExtTermin(143)
+PhysDevExtTramp(144) PhysDevExtTermin(144)
+PhysDevExtTramp(145) PhysDevExtTermin(145)
+PhysDevExtTramp(146) PhysDevExtTermin(146)
+PhysDevExtTramp(147) PhysDevExtTermin(147)
+PhysDevExtTramp(148) PhysDevExtTermin(148)
+PhysDevExtTramp(149) PhysDevExtTermin(149)
+PhysDevExtTramp(150) PhysDevExtTermin(150)
+PhysDevExtTramp(151) PhysDevExtTermin(151)
+PhysDevExtTramp(152) PhysDevExtTermin(152)
+PhysDevExtTramp(153) PhysDevExtTermin(153)
+PhysDevExtTramp(154) PhysDevExtTermin(154)
+PhysDevExtTramp(155) PhysDevExtTermin(155)
+PhysDevExtTramp(156) PhysDevExtTermin(156)
+PhysDevExtTramp(157) PhysDevExtTermin(157)
+PhysDevExtTramp(158) PhysDevExtTermin(158)
+PhysDevExtTramp(159) PhysDevExtTermin(159)
+PhysDevExtTramp(160) PhysDevExtTermin(160)
+PhysDevExtTramp(161) PhysDevExtTermin(161)
+PhysDevExtTramp(162) PhysDevExtTermin(162)
+PhysDevExtTramp(163) PhysDevExtTermin(163)
+PhysDevExtTramp(164) PhysDevExtTermin(164)
+PhysDevExtTramp(165) PhysDevExtTermin(165)
+PhysDevExtTramp(166) PhysDevExtTermin(166)
+PhysDevExtTramp(167) PhysDevExtTermin(167)
+PhysDevExtTramp(168) PhysDevExtTermin(168)
+PhysDevExtTramp(169) PhysDevExtTermin(169)
+PhysDevExtTramp(170) PhysDevExtTermin(170)
+PhysDevExtTramp(171) PhysDevExtTermin(171)
+PhysDevExtTramp(172) PhysDevExtTermin(172)
+PhysDevExtTramp(173) PhysDevExtTermin(173)
+PhysDevExtTramp(174) PhysDevExtTermin(174)
+PhysDevExtTramp(175) PhysDevExtTermin(175)
+PhysDevExtTramp(176) PhysDevExtTermin(176)
+PhysDevExtTramp(177) PhysDevExtTermin(177)
+PhysDevExtTramp(178) PhysDevExtTermin(178)
+PhysDevExtTramp(179) PhysDevExtTermin(179)
+PhysDevExtTramp(180) PhysDevExtTermin(180)
+PhysDevExtTramp(181) PhysDevExtTermin(181)
+PhysDevExtTramp(182) PhysDevExtTermin(182)
+PhysDevExtTramp(183) PhysDevExtTermin(183)
+PhysDevExtTramp(184) PhysDevExtTermin(184)
+PhysDevExtTramp(185) PhysDevExtTermin(185)
+PhysDevExtTramp(186) PhysDevExtTermin(186)
+PhysDevExtTramp(187) PhysDevExtTermin(187)
+PhysDevExtTramp(188) PhysDevExtTermin(188)
+PhysDevExtTramp(189) PhysDevExtTermin(189)
+PhysDevExtTramp(190) PhysDevExtTermin(190)
+PhysDevExtTramp(191) PhysDevExtTermin(191)
+PhysDevExtTramp(192) PhysDevExtTermin(192)
+PhysDevExtTramp(193) PhysDevExtTermin(193)
+PhysDevExtTramp(194) PhysDevExtTermin(194)
+PhysDevExtTramp(195) PhysDevExtTermin(195)
+PhysDevExtTramp(196) PhysDevExtTermin(196)
+PhysDevExtTramp(197) PhysDevExtTermin(197)
+PhysDevExtTramp(198) PhysDevExtTermin(198)
+PhysDevExtTramp(199) PhysDevExtTermin(199)
+PhysDevExtTramp(200) PhysDevExtTermin(200)
+PhysDevExtTramp(201) PhysDevExtTermin(201)
+PhysDevExtTramp(202) PhysDevExtTermin(202)
+PhysDevExtTramp(203) PhysDevExtTermin(203)
+PhysDevExtTramp(204) PhysDevExtTermin(204)
+PhysDevExtTramp(205) PhysDevExtTermin(205)
+PhysDevExtTramp(206) PhysDevExtTermin(206)
+PhysDevExtTramp(207) PhysDevExtTermin(207)
+PhysDevExtTramp(208) PhysDevExtTermin(208)
+PhysDevExtTramp(209) PhysDevExtTermin(209)
+PhysDevExtTramp(210) PhysDevExtTermin(210)
+PhysDevExtTramp(211) PhysDevExtTermin(211)
+PhysDevExtTramp(212) PhysDevExtTermin(212)
+PhysDevExtTramp(213) PhysDevExtTermin(213)
+PhysDevExtTramp(214) PhysDevExtTermin(214)
+PhysDevExtTramp(215) PhysDevExtTermin(215)
+PhysDevExtTramp(216) PhysDevExtTermin(216)
+PhysDevExtTramp(217) PhysDevExtTermin(217)
+PhysDevExtTramp(218) PhysDevExtTermin(218)
+PhysDevExtTramp(219) PhysDevExtTermin(219)
+PhysDevExtTramp(220) PhysDevExtTermin(220)
+PhysDevExtTramp(221) PhysDevExtTermin(221)
+PhysDevExtTramp(222) PhysDevExtTermin(222)
+PhysDevExtTramp(223) PhysDevExtTermin(223)
+PhysDevExtTramp(224) PhysDevExtTermin(224)
+PhysDevExtTramp(225) PhysDevExtTermin(225)
+PhysDevExtTramp(226) PhysDevExtTermin(226)
+PhysDevExtTramp(227) PhysDevExtTermin(227)
+PhysDevExtTramp(228) PhysDevExtTermin(228)
+PhysDevExtTramp(229) PhysDevExtTermin(229)
+PhysDevExtTramp(230) PhysDevExtTermin(230)
+PhysDevExtTramp(231) PhysDevExtTermin(231)
+PhysDevExtTramp(232) PhysDevExtTermin(232)
+PhysDevExtTramp(233) PhysDevExtTermin(233)
+PhysDevExtTramp(234) PhysDevExtTermin(234)
+PhysDevExtTramp(235) PhysDevExtTermin(235)
+PhysDevExtTramp(236) PhysDevExtTermin(236)
+PhysDevExtTramp(237) PhysDevExtTermin(237)
+PhysDevExtTramp(238) PhysDevExtTermin(238)
+PhysDevExtTramp(239) PhysDevExtTermin(239)
+PhysDevExtTramp(240) PhysDevExtTermin(240)
+PhysDevExtTramp(241) PhysDevExtTermin(241)
+PhysDevExtTramp(242) PhysDevExtTermin(242)
+PhysDevExtTramp(243) PhysDevExtTermin(243)
+PhysDevExtTramp(244) PhysDevExtTermin(244)
+PhysDevExtTramp(245) PhysDevExtTermin(245)
+PhysDevExtTramp(246) PhysDevExtTermin(246)
+PhysDevExtTramp(247) PhysDevExtTermin(247)
+PhysDevExtTramp(248) PhysDevExtTermin(248)
+PhysDevExtTramp(249) PhysDevExtTermin(249)
+
+
+void *loader_get_phys_dev_ext_tramp(uint32_t index) {
+    switch (index) {
+#define TRAMP_CASE_HANDLE(num) case num: return vkPhysDevExtTramp##num
+        TRAMP_CASE_HANDLE(0);
+        TRAMP_CASE_HANDLE(1);
+        TRAMP_CASE_HANDLE(2);
+        TRAMP_CASE_HANDLE(3);
+        TRAMP_CASE_HANDLE(4);
+        TRAMP_CASE_HANDLE(5);
+        TRAMP_CASE_HANDLE(6);
+        TRAMP_CASE_HANDLE(7);
+        TRAMP_CASE_HANDLE(8);
+        TRAMP_CASE_HANDLE(9);
+        TRAMP_CASE_HANDLE(10);
+        TRAMP_CASE_HANDLE(11);
+        TRAMP_CASE_HANDLE(12);
+        TRAMP_CASE_HANDLE(13);
+        TRAMP_CASE_HANDLE(14);
+        TRAMP_CASE_HANDLE(15);
+        TRAMP_CASE_HANDLE(16);
+        TRAMP_CASE_HANDLE(17);
+        TRAMP_CASE_HANDLE(18);
+        TRAMP_CASE_HANDLE(19);
+        TRAMP_CASE_HANDLE(20);
+        TRAMP_CASE_HANDLE(21);
+        TRAMP_CASE_HANDLE(22);
+        TRAMP_CASE_HANDLE(23);
+        TRAMP_CASE_HANDLE(24);
+        TRAMP_CASE_HANDLE(25);
+        TRAMP_CASE_HANDLE(26);
+        TRAMP_CASE_HANDLE(27);
+        TRAMP_CASE_HANDLE(28);
+        TRAMP_CASE_HANDLE(29);
+        TRAMP_CASE_HANDLE(30);
+        TRAMP_CASE_HANDLE(31);
+        TRAMP_CASE_HANDLE(32);
+        TRAMP_CASE_HANDLE(33);
+        TRAMP_CASE_HANDLE(34);
+        TRAMP_CASE_HANDLE(35);
+        TRAMP_CASE_HANDLE(36);
+        TRAMP_CASE_HANDLE(37);
+        TRAMP_CASE_HANDLE(38);
+        TRAMP_CASE_HANDLE(39);
+        TRAMP_CASE_HANDLE(40);
+        TRAMP_CASE_HANDLE(41);
+        TRAMP_CASE_HANDLE(42);
+        TRAMP_CASE_HANDLE(43);
+        TRAMP_CASE_HANDLE(44);
+        TRAMP_CASE_HANDLE(45);
+        TRAMP_CASE_HANDLE(46);
+        TRAMP_CASE_HANDLE(47);
+        TRAMP_CASE_HANDLE(48);
+        TRAMP_CASE_HANDLE(49);
+        TRAMP_CASE_HANDLE(50);
+        TRAMP_CASE_HANDLE(51);
+        TRAMP_CASE_HANDLE(52);
+        TRAMP_CASE_HANDLE(53);
+        TRAMP_CASE_HANDLE(54);
+        TRAMP_CASE_HANDLE(55);
+        TRAMP_CASE_HANDLE(56);
+        TRAMP_CASE_HANDLE(57);
+        TRAMP_CASE_HANDLE(58);
+        TRAMP_CASE_HANDLE(59);
+        TRAMP_CASE_HANDLE(60);
+        TRAMP_CASE_HANDLE(61);
+        TRAMP_CASE_HANDLE(62);
+        TRAMP_CASE_HANDLE(63);
+        TRAMP_CASE_HANDLE(64);
+        TRAMP_CASE_HANDLE(65);
+        TRAMP_CASE_HANDLE(66);
+        TRAMP_CASE_HANDLE(67);
+        TRAMP_CASE_HANDLE(68);
+        TRAMP_CASE_HANDLE(69);
+        TRAMP_CASE_HANDLE(70);
+        TRAMP_CASE_HANDLE(71);
+        TRAMP_CASE_HANDLE(72);
+        TRAMP_CASE_HANDLE(73);
+        TRAMP_CASE_HANDLE(74);
+        TRAMP_CASE_HANDLE(75);
+        TRAMP_CASE_HANDLE(76);
+        TRAMP_CASE_HANDLE(77);
+        TRAMP_CASE_HANDLE(78);
+        TRAMP_CASE_HANDLE(79);
+        TRAMP_CASE_HANDLE(80);
+        TRAMP_CASE_HANDLE(81);
+        TRAMP_CASE_HANDLE(82);
+        TRAMP_CASE_HANDLE(83);
+        TRAMP_CASE_HANDLE(84);
+        TRAMP_CASE_HANDLE(85);
+        TRAMP_CASE_HANDLE(86);
+        TRAMP_CASE_HANDLE(87);
+        TRAMP_CASE_HANDLE(88);
+        TRAMP_CASE_HANDLE(89);
+        TRAMP_CASE_HANDLE(90);
+        TRAMP_CASE_HANDLE(91);
+        TRAMP_CASE_HANDLE(92);
+        TRAMP_CASE_HANDLE(93);
+        TRAMP_CASE_HANDLE(94);
+        TRAMP_CASE_HANDLE(95);
+        TRAMP_CASE_HANDLE(96);
+        TRAMP_CASE_HANDLE(97);
+        TRAMP_CASE_HANDLE(98);
+        TRAMP_CASE_HANDLE(99);
+        TRAMP_CASE_HANDLE(100);
+        TRAMP_CASE_HANDLE(101);
+        TRAMP_CASE_HANDLE(102);
+        TRAMP_CASE_HANDLE(103);
+        TRAMP_CASE_HANDLE(104);
+        TRAMP_CASE_HANDLE(105);
+        TRAMP_CASE_HANDLE(106);
+        TRAMP_CASE_HANDLE(107);
+        TRAMP_CASE_HANDLE(108);
+        TRAMP_CASE_HANDLE(109);
+        TRAMP_CASE_HANDLE(110);
+        TRAMP_CASE_HANDLE(111);
+        TRAMP_CASE_HANDLE(112);
+        TRAMP_CASE_HANDLE(113);
+        TRAMP_CASE_HANDLE(114);
+        TRAMP_CASE_HANDLE(115);
+        TRAMP_CASE_HANDLE(116);
+        TRAMP_CASE_HANDLE(117);
+        TRAMP_CASE_HANDLE(118);
+        TRAMP_CASE_HANDLE(119);
+        TRAMP_CASE_HANDLE(120);
+        TRAMP_CASE_HANDLE(121);
+        TRAMP_CASE_HANDLE(122);
+        TRAMP_CASE_HANDLE(123);
+        TRAMP_CASE_HANDLE(124);
+        TRAMP_CASE_HANDLE(125);
+        TRAMP_CASE_HANDLE(126);
+        TRAMP_CASE_HANDLE(127);
+        TRAMP_CASE_HANDLE(128);
+        TRAMP_CASE_HANDLE(129);
+        TRAMP_CASE_HANDLE(130);
+        TRAMP_CASE_HANDLE(131);
+        TRAMP_CASE_HANDLE(132);
+        TRAMP_CASE_HANDLE(133);
+        TRAMP_CASE_HANDLE(134);
+        TRAMP_CASE_HANDLE(135);
+        TRAMP_CASE_HANDLE(136);
+        TRAMP_CASE_HANDLE(137);
+        TRAMP_CASE_HANDLE(138);
+        TRAMP_CASE_HANDLE(139);
+        TRAMP_CASE_HANDLE(140);
+        TRAMP_CASE_HANDLE(141);
+        TRAMP_CASE_HANDLE(142);
+        TRAMP_CASE_HANDLE(143);
+        TRAMP_CASE_HANDLE(144);
+        TRAMP_CASE_HANDLE(145);
+        TRAMP_CASE_HANDLE(146);
+        TRAMP_CASE_HANDLE(147);
+        TRAMP_CASE_HANDLE(148);
+        TRAMP_CASE_HANDLE(149);
+        TRAMP_CASE_HANDLE(150);
+        TRAMP_CASE_HANDLE(151);
+        TRAMP_CASE_HANDLE(152);
+        TRAMP_CASE_HANDLE(153);
+        TRAMP_CASE_HANDLE(154);
+        TRAMP_CASE_HANDLE(155);
+        TRAMP_CASE_HANDLE(156);
+        TRAMP_CASE_HANDLE(157);
+        TRAMP_CASE_HANDLE(158);
+        TRAMP_CASE_HANDLE(159);
+        TRAMP_CASE_HANDLE(160);
+        TRAMP_CASE_HANDLE(161);
+        TRAMP_CASE_HANDLE(162);
+        TRAMP_CASE_HANDLE(163);
+        TRAMP_CASE_HANDLE(164);
+        TRAMP_CASE_HANDLE(165);
+        TRAMP_CASE_HANDLE(166);
+        TRAMP_CASE_HANDLE(167);
+        TRAMP_CASE_HANDLE(168);
+        TRAMP_CASE_HANDLE(169);
+        TRAMP_CASE_HANDLE(170);
+        TRAMP_CASE_HANDLE(171);
+        TRAMP_CASE_HANDLE(172);
+        TRAMP_CASE_HANDLE(173);
+        TRAMP_CASE_HANDLE(174);
+        TRAMP_CASE_HANDLE(175);
+        TRAMP_CASE_HANDLE(176);
+        TRAMP_CASE_HANDLE(177);
+        TRAMP_CASE_HANDLE(178);
+        TRAMP_CASE_HANDLE(179);
+        TRAMP_CASE_HANDLE(180);
+        TRAMP_CASE_HANDLE(181);
+        TRAMP_CASE_HANDLE(182);
+        TRAMP_CASE_HANDLE(183);
+        TRAMP_CASE_HANDLE(184);
+        TRAMP_CASE_HANDLE(185);
+        TRAMP_CASE_HANDLE(186);
+        TRAMP_CASE_HANDLE(187);
+        TRAMP_CASE_HANDLE(188);
+        TRAMP_CASE_HANDLE(189);
+        TRAMP_CASE_HANDLE(190);
+        TRAMP_CASE_HANDLE(191);
+        TRAMP_CASE_HANDLE(192);
+        TRAMP_CASE_HANDLE(193);
+        TRAMP_CASE_HANDLE(194);
+        TRAMP_CASE_HANDLE(195);
+        TRAMP_CASE_HANDLE(196);
+        TRAMP_CASE_HANDLE(197);
+        TRAMP_CASE_HANDLE(198);
+        TRAMP_CASE_HANDLE(199);
+        TRAMP_CASE_HANDLE(200);
+        TRAMP_CASE_HANDLE(201);
+        TRAMP_CASE_HANDLE(202);
+        TRAMP_CASE_HANDLE(203);
+        TRAMP_CASE_HANDLE(204);
+        TRAMP_CASE_HANDLE(205);
+        TRAMP_CASE_HANDLE(206);
+        TRAMP_CASE_HANDLE(207);
+        TRAMP_CASE_HANDLE(208);
+        TRAMP_CASE_HANDLE(209);
+        TRAMP_CASE_HANDLE(210);
+        TRAMP_CASE_HANDLE(211);
+        TRAMP_CASE_HANDLE(212);
+        TRAMP_CASE_HANDLE(213);
+        TRAMP_CASE_HANDLE(214);
+        TRAMP_CASE_HANDLE(215);
+        TRAMP_CASE_HANDLE(216);
+        TRAMP_CASE_HANDLE(217);
+        TRAMP_CASE_HANDLE(218);
+        TRAMP_CASE_HANDLE(219);
+        TRAMP_CASE_HANDLE(220);
+        TRAMP_CASE_HANDLE(221);
+        TRAMP_CASE_HANDLE(222);
+        TRAMP_CASE_HANDLE(223);
+        TRAMP_CASE_HANDLE(224);
+        TRAMP_CASE_HANDLE(225);
+        TRAMP_CASE_HANDLE(226);
+        TRAMP_CASE_HANDLE(227);
+        TRAMP_CASE_HANDLE(228);
+        TRAMP_CASE_HANDLE(229);
+        TRAMP_CASE_HANDLE(230);
+        TRAMP_CASE_HANDLE(231);
+        TRAMP_CASE_HANDLE(232);
+        TRAMP_CASE_HANDLE(233);
+        TRAMP_CASE_HANDLE(234);
+        TRAMP_CASE_HANDLE(235);
+        TRAMP_CASE_HANDLE(236);
+        TRAMP_CASE_HANDLE(237);
+        TRAMP_CASE_HANDLE(238);
+        TRAMP_CASE_HANDLE(239);
+        TRAMP_CASE_HANDLE(240);
+        TRAMP_CASE_HANDLE(241);
+        TRAMP_CASE_HANDLE(242);
+        TRAMP_CASE_HANDLE(243);
+        TRAMP_CASE_HANDLE(244);
+        TRAMP_CASE_HANDLE(245);
+        TRAMP_CASE_HANDLE(246);
+        TRAMP_CASE_HANDLE(247);
+        TRAMP_CASE_HANDLE(248);
+        TRAMP_CASE_HANDLE(249);
+    }
+    return NULL;
+}
+
+void *loader_get_phys_dev_ext_termin(uint32_t index) {
+    switch (index) {
+#define TERM_CASE_HANDLE(num) case num: return vkPhysDevExtTermin##num
+        TERM_CASE_HANDLE(0);
+        TERM_CASE_HANDLE(1);
+        TERM_CASE_HANDLE(2);
+        TERM_CASE_HANDLE(3);
+        TERM_CASE_HANDLE(4);
+        TERM_CASE_HANDLE(5);
+        TERM_CASE_HANDLE(6);
+        TERM_CASE_HANDLE(7);
+        TERM_CASE_HANDLE(8);
+        TERM_CASE_HANDLE(9);
+        TERM_CASE_HANDLE(10);
+        TERM_CASE_HANDLE(11);
+        TERM_CASE_HANDLE(12);
+        TERM_CASE_HANDLE(13);
+        TERM_CASE_HANDLE(14);
+        TERM_CASE_HANDLE(15);
+        TERM_CASE_HANDLE(16);
+        TERM_CASE_HANDLE(17);
+        TERM_CASE_HANDLE(18);
+        TERM_CASE_HANDLE(19);
+        TERM_CASE_HANDLE(20);
+        TERM_CASE_HANDLE(21);
+        TERM_CASE_HANDLE(22);
+        TERM_CASE_HANDLE(23);
+        TERM_CASE_HANDLE(24);
+        TERM_CASE_HANDLE(25);
+        TERM_CASE_HANDLE(26);
+        TERM_CASE_HANDLE(27);
+        TERM_CASE_HANDLE(28);
+        TERM_CASE_HANDLE(29);
+        TERM_CASE_HANDLE(30);
+        TERM_CASE_HANDLE(31);
+        TERM_CASE_HANDLE(32);
+        TERM_CASE_HANDLE(33);
+        TERM_CASE_HANDLE(34);
+        TERM_CASE_HANDLE(35);
+        TERM_CASE_HANDLE(36);
+        TERM_CASE_HANDLE(37);
+        TERM_CASE_HANDLE(38);
+        TERM_CASE_HANDLE(39);
+        TERM_CASE_HANDLE(40);
+        TERM_CASE_HANDLE(41);
+        TERM_CASE_HANDLE(42);
+        TERM_CASE_HANDLE(43);
+        TERM_CASE_HANDLE(44);
+        TERM_CASE_HANDLE(45);
+        TERM_CASE_HANDLE(46);
+        TERM_CASE_HANDLE(47);
+        TERM_CASE_HANDLE(48);
+        TERM_CASE_HANDLE(49);
+        TERM_CASE_HANDLE(50);
+        TERM_CASE_HANDLE(51);
+        TERM_CASE_HANDLE(52);
+        TERM_CASE_HANDLE(53);
+        TERM_CASE_HANDLE(54);
+        TERM_CASE_HANDLE(55);
+        TERM_CASE_HANDLE(56);
+        TERM_CASE_HANDLE(57);
+        TERM_CASE_HANDLE(58);
+        TERM_CASE_HANDLE(59);
+        TERM_CASE_HANDLE(60);
+        TERM_CASE_HANDLE(61);
+        TERM_CASE_HANDLE(62);
+        TERM_CASE_HANDLE(63);
+        TERM_CASE_HANDLE(64);
+        TERM_CASE_HANDLE(65);
+        TERM_CASE_HANDLE(66);
+        TERM_CASE_HANDLE(67);
+        TERM_CASE_HANDLE(68);
+        TERM_CASE_HANDLE(69);
+        TERM_CASE_HANDLE(70);
+        TERM_CASE_HANDLE(71);
+        TERM_CASE_HANDLE(72);
+        TERM_CASE_HANDLE(73);
+        TERM_CASE_HANDLE(74);
+        TERM_CASE_HANDLE(75);
+        TERM_CASE_HANDLE(76);
+        TERM_CASE_HANDLE(77);
+        TERM_CASE_HANDLE(78);
+        TERM_CASE_HANDLE(79);
+        TERM_CASE_HANDLE(80);
+        TERM_CASE_HANDLE(81);
+        TERM_CASE_HANDLE(82);
+        TERM_CASE_HANDLE(83);
+        TERM_CASE_HANDLE(84);
+        TERM_CASE_HANDLE(85);
+        TERM_CASE_HANDLE(86);
+        TERM_CASE_HANDLE(87);
+        TERM_CASE_HANDLE(88);
+        TERM_CASE_HANDLE(89);
+        TERM_CASE_HANDLE(90);
+        TERM_CASE_HANDLE(91);
+        TERM_CASE_HANDLE(92);
+        TERM_CASE_HANDLE(93);
+        TERM_CASE_HANDLE(94);
+        TERM_CASE_HANDLE(95);
+        TERM_CASE_HANDLE(96);
+        TERM_CASE_HANDLE(97);
+        TERM_CASE_HANDLE(98);
+        TERM_CASE_HANDLE(99);
+        TERM_CASE_HANDLE(100);
+        TERM_CASE_HANDLE(101);
+        TERM_CASE_HANDLE(102);
+        TERM_CASE_HANDLE(103);
+        TERM_CASE_HANDLE(104);
+        TERM_CASE_HANDLE(105);
+        TERM_CASE_HANDLE(106);
+        TERM_CASE_HANDLE(107);
+        TERM_CASE_HANDLE(108);
+        TERM_CASE_HANDLE(109);
+        TERM_CASE_HANDLE(110);
+        TERM_CASE_HANDLE(111);
+        TERM_CASE_HANDLE(112);
+        TERM_CASE_HANDLE(113);
+        TERM_CASE_HANDLE(114);
+        TERM_CASE_HANDLE(115);
+        TERM_CASE_HANDLE(116);
+        TERM_CASE_HANDLE(117);
+        TERM_CASE_HANDLE(118);
+        TERM_CASE_HANDLE(119);
+        TERM_CASE_HANDLE(120);
+        TERM_CASE_HANDLE(121);
+        TERM_CASE_HANDLE(122);
+        TERM_CASE_HANDLE(123);
+        TERM_CASE_HANDLE(124);
+        TERM_CASE_HANDLE(125);
+        TERM_CASE_HANDLE(126);
+        TERM_CASE_HANDLE(127);
+        TERM_CASE_HANDLE(128);
+        TERM_CASE_HANDLE(129);
+        TERM_CASE_HANDLE(130);
+        TERM_CASE_HANDLE(131);
+        TERM_CASE_HANDLE(132);
+        TERM_CASE_HANDLE(133);
+        TERM_CASE_HANDLE(134);
+        TERM_CASE_HANDLE(135);
+        TERM_CASE_HANDLE(136);
+        TERM_CASE_HANDLE(137);
+        TERM_CASE_HANDLE(138);
+        TERM_CASE_HANDLE(139);
+        TERM_CASE_HANDLE(140);
+        TERM_CASE_HANDLE(141);
+        TERM_CASE_HANDLE(142);
+        TERM_CASE_HANDLE(143);
+        TERM_CASE_HANDLE(144);
+        TERM_CASE_HANDLE(145);
+        TERM_CASE_HANDLE(146);
+        TERM_CASE_HANDLE(147);
+        TERM_CASE_HANDLE(148);
+        TERM_CASE_HANDLE(149);
+        TERM_CASE_HANDLE(150);
+        TERM_CASE_HANDLE(151);
+        TERM_CASE_HANDLE(152);
+        TERM_CASE_HANDLE(153);
+        TERM_CASE_HANDLE(154);
+        TERM_CASE_HANDLE(155);
+        TERM_CASE_HANDLE(156);
+        TERM_CASE_HANDLE(157);
+        TERM_CASE_HANDLE(158);
+        TERM_CASE_HANDLE(159);
+        TERM_CASE_HANDLE(160);
+        TERM_CASE_HANDLE(161);
+        TERM_CASE_HANDLE(162);
+        TERM_CASE_HANDLE(163);
+        TERM_CASE_HANDLE(164);
+        TERM_CASE_HANDLE(165);
+        TERM_CASE_HANDLE(166);
+        TERM_CASE_HANDLE(167);
+        TERM_CASE_HANDLE(168);
+        TERM_CASE_HANDLE(169);
+        TERM_CASE_HANDLE(170);
+        TERM_CASE_HANDLE(171);
+        TERM_CASE_HANDLE(172);
+        TERM_CASE_HANDLE(173);
+        TERM_CASE_HANDLE(174);
+        TERM_CASE_HANDLE(175);
+        TERM_CASE_HANDLE(176);
+        TERM_CASE_HANDLE(177);
+        TERM_CASE_HANDLE(178);
+        TERM_CASE_HANDLE(179);
+        TERM_CASE_HANDLE(180);
+        TERM_CASE_HANDLE(181);
+        TERM_CASE_HANDLE(182);
+        TERM_CASE_HANDLE(183);
+        TERM_CASE_HANDLE(184);
+        TERM_CASE_HANDLE(185);
+        TERM_CASE_HANDLE(186);
+        TERM_CASE_HANDLE(187);
+        TERM_CASE_HANDLE(188);
+        TERM_CASE_HANDLE(189);
+        TERM_CASE_HANDLE(190);
+        TERM_CASE_HANDLE(191);
+        TERM_CASE_HANDLE(192);
+        TERM_CASE_HANDLE(193);
+        TERM_CASE_HANDLE(194);
+        TERM_CASE_HANDLE(195);
+        TERM_CASE_HANDLE(196);
+        TERM_CASE_HANDLE(197);
+        TERM_CASE_HANDLE(198);
+        TERM_CASE_HANDLE(199);
+        TERM_CASE_HANDLE(200);
+        TERM_CASE_HANDLE(201);
+        TERM_CASE_HANDLE(202);
+        TERM_CASE_HANDLE(203);
+        TERM_CASE_HANDLE(204);
+        TERM_CASE_HANDLE(205);
+        TERM_CASE_HANDLE(206);
+        TERM_CASE_HANDLE(207);
+        TERM_CASE_HANDLE(208);
+        TERM_CASE_HANDLE(209);
+        TERM_CASE_HANDLE(210);
+        TERM_CASE_HANDLE(211);
+        TERM_CASE_HANDLE(212);
+        TERM_CASE_HANDLE(213);
+        TERM_CASE_HANDLE(214);
+        TERM_CASE_HANDLE(215);
+        TERM_CASE_HANDLE(216);
+        TERM_CASE_HANDLE(217);
+        TERM_CASE_HANDLE(218);
+        TERM_CASE_HANDLE(219);
+        TERM_CASE_HANDLE(220);
+        TERM_CASE_HANDLE(221);
+        TERM_CASE_HANDLE(222);
+        TERM_CASE_HANDLE(223);
+        TERM_CASE_HANDLE(224);
+        TERM_CASE_HANDLE(225);
+        TERM_CASE_HANDLE(226);
+        TERM_CASE_HANDLE(227);
+        TERM_CASE_HANDLE(228);
+        TERM_CASE_HANDLE(229);
+        TERM_CASE_HANDLE(230);
+        TERM_CASE_HANDLE(231);
+        TERM_CASE_HANDLE(232);
+        TERM_CASE_HANDLE(233);
+        TERM_CASE_HANDLE(234);
+        TERM_CASE_HANDLE(235);
+        TERM_CASE_HANDLE(236);
+        TERM_CASE_HANDLE(237);
+        TERM_CASE_HANDLE(238);
+        TERM_CASE_HANDLE(239);
+        TERM_CASE_HANDLE(240);
+        TERM_CASE_HANDLE(241);
+        TERM_CASE_HANDLE(242);
+        TERM_CASE_HANDLE(243);
+        TERM_CASE_HANDLE(244);
+        TERM_CASE_HANDLE(245);
+        TERM_CASE_HANDLE(246);
+        TERM_CASE_HANDLE(247);
+        TERM_CASE_HANDLE(248);
+        TERM_CASE_HANDLE(249);
+    }
+    return NULL;
+}
diff --git a/loader/table_ops.h b/loader/table_ops.h
index eecc952..b3b9079 100644
--- a/loader/table_ops.h
+++ b/loader/table_ops.h
@@ -46,7 +46,7 @@
 loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table,
                                   PFN_vkGetDeviceProcAddr gpa, VkDevice dev) {
     VkLayerDispatchTable *table = &dev_table->core_dispatch;
-    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++)
+    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++)
         dev_table->ext_dispatch.dev_ext[i] = (PFN_vkDevExt)vkDevExtError;
 
     table->GetDeviceProcAddr =
@@ -269,21 +269,30 @@
         (PFN_vkGetSwapchainImagesKHR)gpa(dev, "vkGetSwapchainImagesKHR");
     table->QueuePresentKHR =
         (PFN_vkQueuePresentKHR)gpa(dev, "vkQueuePresentKHR");
-    table->CmdDrawIndirectCountAMD =
-        (PFN_vkCmdDrawIndirectCountAMD)gpa(dev, "vkCmdDrawIndirectCountAMD");
-    table->CmdDrawIndexedIndirectCountAMD =
-        (PFN_vkCmdDrawIndexedIndirectCountAMD)gpa(
-            dev, "vkCmdDrawIndexedIndirectCountAMD");
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-    table->GetMemoryWin32HandleNV =
-        (PFN_vkGetMemoryWin32HandleNV)gpa(dev, "vkGetMemoryWin32HandleNV");
-#endif // VK_USE_PLATFORM_WIN32_KHR
-    table->CreateSharedSwapchainsKHR =
-        (PFN_vkCreateSharedSwapchainsKHR)gpa(dev, "vkCreateSharedSwapchainsKHR");
-    table->DebugMarkerSetObjectTagEXT =
-        (PFN_vkDebugMarkerSetObjectTagEXT)gpa(dev, "vkDebugMarkerSetObjectTagEXT");
-    table->DebugMarkerSetObjectNameEXT =
-        (PFN_vkDebugMarkerSetObjectNameEXT)gpa(dev, "vkDebugMarkerSetObjectNameEXT");
+
+    // KHR_display_swapchain
+    table->CreateSharedSwapchainsKHR = (PFN_vkCreateSharedSwapchainsKHR)gpa(
+        dev, "vkCreateSharedSwapchainsKHR");
+
+    // KHR_maintenance1
+    table->TrimCommandPoolKHR =
+        (PFN_vkTrimCommandPoolKHR)gpa(dev, "vkTrimCommandPoolKHR");
+
+    // EXT_display_control
+    table->DisplayPowerControlEXT =
+        (PFN_vkDisplayPowerControlEXT)gpa(dev, "vkDisplayPowerControlEXT");
+    table->RegisterDeviceEventEXT =
+        (PFN_vkRegisterDeviceEventEXT)gpa(dev, "vkRegisterDeviceEventEXT");
+    table->RegisterDisplayEventEXT =
+        (PFN_vkRegisterDisplayEventEXT)gpa(dev, "vkRegisterDisplayEventEXT");
+    table->GetSwapchainCounterEXT =
+        (PFN_vkGetSwapchainCounterEXT)gpa(dev, "vkGetSwapchainCounterEXT");
+
+    // EXT_debug_marker
+    table->DebugMarkerSetObjectTagEXT = (PFN_vkDebugMarkerSetObjectTagEXT)gpa(
+        dev, "vkDebugMarkerSetObjectTagEXT");
+    table->DebugMarkerSetObjectNameEXT = (PFN_vkDebugMarkerSetObjectNameEXT)gpa(
+        dev, "vkDebugMarkerSetObjectNameEXT");
     table->CmdDebugMarkerBeginEXT =
         (PFN_vkCmdDebugMarkerBeginEXT)gpa(dev, "vkCmdDebugMarkerBeginEXT");
     table->CmdDebugMarkerEndEXT =
@@ -291,6 +300,19 @@
     table->CmdDebugMarkerInsertEXT =
         (PFN_vkCmdDebugMarkerInsertEXT)gpa(dev, "vkCmdDebugMarkerInsertEXT");
 
+    // AMD_draw_indirect_count
+    table->CmdDrawIndirectCountAMD =
+        (PFN_vkCmdDrawIndirectCountAMD)gpa(dev, "vkCmdDrawIndirectCountAMD");
+    table->CmdDrawIndexedIndirectCountAMD =
+        (PFN_vkCmdDrawIndexedIndirectCountAMD)gpa(
+            dev, "vkCmdDrawIndexedIndirectCountAMD");
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+    // NV_external_memory_win32
+    table->GetMemoryWin32HandleNV =
+        (PFN_vkGetMemoryWin32HandleNV)gpa(dev, "vkGetMemoryWin32HandleNV");
+#endif
+
     // NVX_device_generated_commands
     table->CmdProcessCommandsNVX =
         (PFN_vkCmdProcessCommandsNVX)gpa(dev, "vkCmdProcessCommandsNVX");
@@ -562,7 +584,6 @@
         return (void *)table->CmdEndRenderPass;
     if (!strcmp(name, "CmdExecuteCommands"))
         return (void *)table->CmdExecuteCommands;
-
     if (!strcmp(name, "DestroySwapchainKHR"))
         return (void *)table->DestroySwapchainKHR;
     if (!strcmp(name, "GetSwapchainImagesKHR"))
@@ -580,6 +601,8 @@
     // object before passing the appropriate info along to the ICD.
     if (!strcmp(name, "CreateSwapchainKHR")) {
         return (void *)vkCreateSwapchainKHR;
+    } else if (!strcmp(name, "CreateSharedSwapchainsKHR")) {
+        return (void *)vkCreateSharedSwapchainsKHR;
     } else if (!strcmp(name, "DebugMarkerSetObjectTagEXT")) {
         return (void *)vkDebugMarkerSetObjectTagEXT;
     } else if (!strcmp(name, "DebugMarkerSetObjectNameEXT")) {
@@ -629,16 +652,9 @@
 static inline void loader_init_instance_extension_dispatch_table(
     VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,
     VkInstance inst) {
+    // WSI extensions
     table->DestroySurfaceKHR =
         (PFN_vkDestroySurfaceKHR)gpa(inst, "vkDestroySurfaceKHR");
-    table->CreateDebugReportCallbackEXT =
-        (PFN_vkCreateDebugReportCallbackEXT)gpa(
-            inst, "vkCreateDebugReportCallbackEXT");
-    table->DestroyDebugReportCallbackEXT =
-        (PFN_vkDestroyDebugReportCallbackEXT)gpa(
-            inst, "vkDestroyDebugReportCallbackEXT");
-    table->DebugReportMessageEXT =
-        (PFN_vkDebugReportMessageEXT)gpa(inst, "vkDebugReportMessageEXT");
     table->GetPhysicalDeviceSurfaceSupportKHR =
         (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)gpa(
             inst, "vkGetPhysicalDeviceSurfaceSupportKHR");
@@ -651,9 +667,6 @@
     table->GetPhysicalDeviceSurfacePresentModesKHR =
         (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)gpa(
             inst, "vkGetPhysicalDeviceSurfacePresentModesKHR");
-    table->GetPhysicalDeviceExternalImageFormatPropertiesNV =
-        (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)gpa(
-            inst, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV");
 #ifdef VK_USE_PLATFORM_MIR_KHR
     table->CreateMirSurfaceKHR =
         (PFN_vkCreateMirSurfaceKHR)gpa(inst, "vkCreateMirSurfaceKHR");
@@ -709,12 +722,125 @@
         (PFN_vkCreateDisplayPlaneSurfaceKHR)gpa(
             inst, "vkCreateDisplayPlaneSurfaceKHR");
 
-    // NVX_device_generated_commands (physical device commands)
+    // KHR_get_physical_device_properties2
+    table->GetPhysicalDeviceFeatures2KHR =
+        (PFN_vkGetPhysicalDeviceFeatures2KHR)gpa(
+            inst, "vkGetPhysicalDeviceFeatures2KHR");
+    table->GetPhysicalDeviceProperties2KHR =
+        (PFN_vkGetPhysicalDeviceProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceProperties2KHR");
+    table->GetPhysicalDeviceFormatProperties2KHR =
+        (PFN_vkGetPhysicalDeviceFormatProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceFormatProperties2KHR");
+    table->GetPhysicalDeviceImageFormatProperties2KHR =
+        (PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceImageFormatProperties2KHR");
+    table->GetPhysicalDeviceQueueFamilyProperties2KHR =
+        (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
+    table->GetPhysicalDeviceMemoryProperties2KHR =
+        (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceMemoryProperties2KHR");
+    table->GetPhysicalDeviceSparseImageFormatProperties2KHR =
+        (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)gpa(
+            inst, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    // EXT_acquire_xlib_display
+    table->AcquireXlibDisplayEXT =
+        (PFN_vkAcquireXlibDisplayEXT)gpa(inst, "vkAcquireXlibDisplayEXT");
+    table->GetRandROutputDisplayEXT =
+        (PFN_vkGetRandROutputDisplayEXT)gpa(inst, "vkGetRandROutputDisplayEXT");
+#endif
+
+    // EXT_debug_report
+    table->CreateDebugReportCallbackEXT =
+        (PFN_vkCreateDebugReportCallbackEXT)gpa(
+            inst, "vkCreateDebugReportCallbackEXT");
+    table->DestroyDebugReportCallbackEXT =
+        (PFN_vkDestroyDebugReportCallbackEXT)gpa(
+            inst, "vkDestroyDebugReportCallbackEXT");
+    table->DebugReportMessageEXT =
+        (PFN_vkDebugReportMessageEXT)gpa(inst, "vkDebugReportMessageEXT");
+
+    // EXT_direct_mode_display
+    table->ReleaseDisplayEXT =
+        (PFN_vkReleaseDisplayEXT)gpa(inst, "vkReleaseDisplayEXT");
+
+    // EXT_display_surface_counter
+    table->GetPhysicalDeviceSurfaceCapabilities2EXT =
+        (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)gpa(
+            inst, "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
+
+    // NV_external_memory_capabilities
+    table->GetPhysicalDeviceExternalImageFormatPropertiesNV =
+        (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)gpa(
+            inst, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV");
+
+    // NVX_device_generated_commands (physical device command)
     table->GetPhysicalDeviceGeneratedCommandsPropertiesNVX =
         (PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)gpa(
             inst, "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX");
 }
 
+static inline void *loader_lookup_instance_extension_dispatch_table(
+    const VkLayerInstanceDispatchTable *table, const char *name,
+    bool *found_name) {
+
+    *found_name = true;
+
+    // KHR_get_physical_device_properties2
+    if (!strcmp(name, "GetPhysicalDeviceFeatures2KHR"))
+        return (void *)table->GetPhysicalDeviceFeatures2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceFormatProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceFormatProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceImageFormatProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceImageFormatProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceQueueFamilyProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceQueueFamilyProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceMemoryProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceMemoryProperties2KHR;
+    if (!strcmp(name, "GetPhysicalDeviceSparseImageFormatProperties2KHR"))
+        return (void *)table->GetPhysicalDeviceSparseImageFormatProperties2KHR;
+
+// EXT_acquire_xlib_display
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+    if (!strcmp(name, "AcquireXlibDisplayEXT"))
+        return (void *)table->AcquireXlibDisplayEXT;
+    if (!strcmp(name, "GetRandROutputDisplayEXT"))
+        return (void *)table->GetRandROutputDisplayEXT;
+#endif
+
+    // EXT_debug_report
+    if (!strcmp(name, "CreateDebugReportCallbackEXT"))
+        return (void *)table->CreateDebugReportCallbackEXT;
+    if (!strcmp(name, "DestroyDebugReportCallbackEXT"))
+        return (void *)table->DestroyDebugReportCallbackEXT;
+    if (!strcmp(name, "DebugReportMessageEXT"))
+        return (void *)table->DebugReportMessageEXT;
+
+    // EXT_direct_mode_display
+    if (!strcmp(name, "ReleaseDisplayEXT"))
+        return (void *)table->ReleaseDisplayEXT;
+
+    // EXT_display_surface_counter
+    if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilities2EXT"))
+        return (void *)table->GetPhysicalDeviceSurfaceCapabilities2EXT;
+
+    // NV_external_memory_capabilities
+    if (!strcmp(name, "GetPhysicalDeviceExternalImageFormatPropertiesNV"))
+        return (void *)table->GetPhysicalDeviceExternalImageFormatPropertiesNV;
+
+    // NVX_device_generated_commands
+    if (!strcmp(name, "GetPhysicalDeviceGeneratedCommandsPropertiesNVX"))
+        return (void *)table->GetPhysicalDeviceGeneratedCommandsPropertiesNVX;
+
+    *found_name = false;
+    return NULL;
+}
+
 static inline void *
 loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table,
                                       const char *name, bool *found_name) {
@@ -759,8 +885,6 @@
         return (void *)table->GetPhysicalDeviceSurfaceFormatsKHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfacePresentModesKHR"))
         return (void *)table->GetPhysicalDeviceSurfacePresentModesKHR;
-    if (!strcmp(name, "GetPhysicalDeviceExternalImageFormatPropertiesNV"))
-        return (void *)table->GetPhysicalDeviceExternalImageFormatPropertiesNV;
 #ifdef VK_USE_PLATFORM_MIR_KHR
     if (!strcmp(name, "CreateMirSurfaceKHR"))
         return (void *)table->CreateMirSurfaceKHR;
@@ -806,17 +930,6 @@
     if (!strcmp(name, "CreateDisplayPlaneSurfaceKHR"))
         return (void *)table->CreateDisplayPlaneSurfaceKHR;
 
-    if (!strcmp(name, "CreateDebugReportCallbackEXT"))
-        return (void *)table->CreateDebugReportCallbackEXT;
-    if (!strcmp(name, "DestroyDebugReportCallbackEXT"))
-        return (void *)table->DestroyDebugReportCallbackEXT;
-    if (!strcmp(name, "DebugReportMessageEXT"))
-        return (void *)table->DebugReportMessageEXT;
-
-    // NVX_device_generated_commands
-    if (!strcmp(name, "GetPhysicalDeviceGeneratedCommandsPropertiesNVX"))
-        return (void *)table->GetPhysicalDeviceGeneratedCommandsPropertiesNVX;
-
-    *found_name = false;
-    return NULL;
+    return loader_lookup_instance_extension_dispatch_table(table, name,
+                                                           found_name);
 }
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 257ece7..4d14f58 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -409,6 +409,8 @@
                                        &created_instance);
 
     if (res == VK_SUCCESS) {
+        memset(ptr_instance->enabled_known_extensions.padding, 0, sizeof(uint64_t) * 4);
+
         wsi_create_instance(ptr_instance, &ici);
         debug_report_create_instance(ptr_instance, &ici);
         extensions_create_instance(ptr_instance, &ici);
@@ -484,7 +486,7 @@
         return;
     }
 
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
 
     loader_platform_thread_lock_mutex(&loader_lock);
 
@@ -508,6 +510,7 @@
 
     loader_deactivate_layers(ptr_instance, NULL,
                              &ptr_instance->activated_layer_list);
+
     if (ptr_instance->phys_devs_tramp) {
         for (uint32_t i = 0; i < ptr_instance->phys_dev_count_tramp; i++) {
             loader_instance_heap_free(ptr_instance,
@@ -515,6 +518,7 @@
         }
         loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_tramp);
     }
+
     if (callback_setup) {
         util_DestroyDebugReportCallbacks(ptr_instance, pAllocator,
                                          ptr_instance->num_tmp_callbacks,
@@ -535,7 +539,7 @@
     VkResult res = VK_SUCCESS;
     uint32_t count, i;
     struct loader_instance *inst;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
 
     loader_platform_thread_lock_mutex(&loader_lock);
 
@@ -594,7 +598,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceFeatures(unwrapped_phys_dev, pFeatures);
 }
 
@@ -604,7 +608,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_pd =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceFormatProperties(unwrapped_pd, format, pFormatInfo);
 }
 
@@ -616,7 +620,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     return disp->GetPhysicalDeviceImageFormatProperties(
         unwrapped_phys_dev, format, type, tiling, usage, flags,
         pImageFormatProperties);
@@ -627,7 +631,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceProperties(unwrapped_phys_dev, pProperties);
 }
 
@@ -638,7 +642,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceQueueFamilyProperties(
         unwrapped_phys_dev, pQueueFamilyPropertyCount, pQueueProperties);
 }
@@ -649,7 +653,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     disp->GetPhysicalDeviceMemoryProperties(unwrapped_phys_dev,
                                             pMemoryProperties);
 }
@@ -682,7 +686,7 @@
     }
 
     res = loader_add_device_extensions(
-        inst, inst->disp->EnumerateDeviceExtensionProperties,
+        inst, inst->disp->layer_inst_disp.EnumerateDeviceExtensionProperties,
         phys_dev->phys_dev, "Unknown", &icd_exts);
     if (res != VK_SUCCESS) {
         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
@@ -801,7 +805,7 @@
     if (pLayerName == NULL || strlen(pLayerName) == 0) {
         const VkLayerInstanceDispatchTable *disp;
 
-        disp = loader_get_instance_dispatch(physicalDevice);
+        disp = loader_get_instance_layer_dispatch(physicalDevice);
         res = disp->EnumerateDeviceExtensionProperties(
             phys_dev->phys_dev, NULL, pPropertyCount, pProperties);
     } else {
@@ -1147,7 +1151,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
 
     disp->GetPhysicalDeviceSparseImageFormatProperties(
         unwrapped_phys_dev, format, type, samples, usage, tiling,
diff --git a/loader/vulkan-1.def b/loader/vulkan-1.def
index e8e3626..2f67eb4 100644
--- a/loader/vulkan-1.def
+++ b/loader/vulkan-1.def
@@ -1,9 +1,9 @@
 
 ;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;
-; Copyright (c) 2015-2016 The Khronos Group Inc.
-; Copyright (c) 2015-2016 Valve Corporation
-; Copyright (c) 2015-2016 LunarG, Inc.
+; Copyright (c) 2015-2017 The Khronos Group Inc.
+; Copyright (c) 2015-2017 Valve Corporation
+; Copyright (c) 2015-2017 LunarG, Inc.
 ;
 ; Licensed under the Apache License, Version 2.0 (the "License");
 ; you may not use this file except in compliance with the License.
diff --git a/loader/wsi.c b/loader/wsi.c
index c577063..b2e96f8 100644
--- a/loader/wsi.c
+++ b/loader/wsi.c
@@ -152,7 +152,7 @@
 vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
                     const VkAllocationCallbacks *pAllocator) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     disp->DestroySurfaceKHR(instance, surface, pAllocator);
 }
 
@@ -205,7 +205,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceSurfaceSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex, surface, pSupported);
     return res;
@@ -261,7 +261,7 @@
     const VkLayerInstanceDispatchTable *disp;
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceSurfaceCapabilitiesKHR(
         unwrapped_phys_dev, surface, pSurfaceCapabilities);
     return res;
@@ -317,7 +317,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceSurfaceFormatsKHR(
         unwrapped_phys_dev, surface, pSurfaceFormatCount, pSurfaceFormats);
     return res;
@@ -373,7 +373,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceSurfacePresentModesKHR(
         unwrapped_phys_dev, surface, pPresentModeCount, pPresentModes);
     return res;
@@ -548,7 +548,7 @@
     VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res = disp->CreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator,
@@ -638,7 +638,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkBool32 res = disp->GetPhysicalDeviceWin32PresentationSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex);
     return res;
@@ -682,7 +682,7 @@
     VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res =
@@ -771,7 +771,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkBool32 res = disp->GetPhysicalDeviceMirPresentationSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex, connection);
     return res;
@@ -818,7 +818,7 @@
     VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res = disp->CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator,
@@ -907,7 +907,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkBool32 res = disp->GetPhysicalDeviceWaylandPresentationSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex, display);
     return res;
@@ -953,7 +953,7 @@
     VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res =
@@ -1043,7 +1043,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkBool32 res = disp->GetPhysicalDeviceXcbPresentationSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex, connection, visual_id);
     return res;
@@ -1089,7 +1089,7 @@
     VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res =
@@ -1178,7 +1178,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkBool32 res = disp->GetPhysicalDeviceXlibPresentationSupportKHR(
         unwrapped_phys_dev, queueFamilyIndex, dpy, visualID);
     return res;
@@ -1224,7 +1224,7 @@
     VkInstance instance, ANativeWindow *window,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res = disp->CreateAndroidSurfaceKHR(instance, window, pAllocator, pSurface);
@@ -1271,7 +1271,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceDisplayPropertiesKHR(
         unwrapped_phys_dev, pPropertyCount, pProperties);
     return res;
@@ -1309,7 +1309,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetPhysicalDeviceDisplayPlanePropertiesKHR(
         unwrapped_phys_dev, pPropertyCount, pProperties);
     return res;
@@ -1351,7 +1351,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetDisplayPlaneSupportedDisplaysKHR(
         unwrapped_phys_dev, planeIndex, pDisplayCount, pDisplays);
     return res;
@@ -1388,7 +1388,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetDisplayModePropertiesKHR(
         unwrapped_phys_dev, display, pPropertyCount, pProperties);
     return res;
@@ -1426,7 +1426,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->CreateDisplayModeKHR(unwrapped_phys_dev, display,
                                               pCreateInfo, pAllocator, pMode);
     return res;
@@ -1464,7 +1464,7 @@
     VkPhysicalDevice unwrapped_phys_dev =
         loader_unwrap_physical_device(physicalDevice);
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(physicalDevice);
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
     VkResult res = disp->GetDisplayPlaneCapabilitiesKHR(
         unwrapped_phys_dev, mode, planeIndex, pCapabilities);
     return res;
@@ -1499,7 +1499,7 @@
     VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
     const VkLayerInstanceDispatchTable *disp;
-    disp = loader_get_instance_dispatch(instance);
+    disp = loader_get_instance_layer_dispatch(instance);
     VkResult res;
 
     res = disp->CreateDisplayPlaneSurfaceKHR(instance, pCreateInfo, pAllocator,
@@ -1581,8 +1581,8 @@
     return vkRes;
 }
 
-// This is the trampoline entrypoint
-// for CreateSharedSwapchainsKHR
+// EXT_display_swapchain Extension command
+
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR(
     VkDevice device, uint32_t swapchainCount,
     const VkSwapchainCreateInfoKHR *pCreateInfos,
@@ -1593,6 +1593,47 @@
                                            pAllocator, pSwapchains);
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL terminator_vkCreateSharedSwapchainsKHR(
+    VkDevice device, uint32_t swapchainCount,
+    const VkSwapchainCreateInfoKHR *pCreateInfos,
+    const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
+    uint32_t icd_index = 0;
+    struct loader_device *dev;
+    struct loader_icd_term *icd_term =
+        loader_get_icd_and_device(device, &dev, &icd_index);
+    if (NULL != icd_term && NULL != icd_term->CreateSharedSwapchainsKHR) {
+        VkIcdSurface *icd_surface =
+            (VkIcdSurface *)(uintptr_t)pCreateInfos->surface;
+        if (NULL != icd_surface->real_icd_surfaces) {
+            if ((VkSurfaceKHR)NULL !=
+                icd_surface->real_icd_surfaces[icd_index]) {
+                // We found the ICD, and there is an ICD KHR surface
+                // associated with it, so copy the CreateInfo struct
+                // and point it at the ICD's surface.
+                VkSwapchainCreateInfoKHR *pCreateCopy =
+                    loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR) *
+                        swapchainCount);
+                if (NULL == pCreateCopy) {
+                    return VK_ERROR_OUT_OF_HOST_MEMORY;
+                }
+                memcpy(pCreateCopy, pCreateInfos,
+                       sizeof(VkSwapchainCreateInfoKHR) * swapchainCount);
+                for (uint32_t sc = 0; sc < swapchainCount; sc++) {
+                    pCreateCopy[sc].surface =
+                        icd_surface->real_icd_surfaces[icd_index];
+                }
+                return icd_term->CreateSharedSwapchainsKHR(
+                    device, swapchainCount, pCreateCopy, pAllocator,
+                    pSwapchains);
+            }
+        }
+        return icd_term->CreateSharedSwapchainsKHR(device, swapchainCount,
+                                                   pCreateInfos, pAllocator,
+                                                   pSwapchains);
+    }
+    return VK_SUCCESS;
+}
+
 bool wsi_swapchain_instance_gpa(struct loader_instance *ptr_instance,
                                 const char *name, void **addr) {
     *addr = NULL;
diff --git a/loader/wsi.h b/loader/wsi.h
index 77cc183..b93a53c 100644
--- a/loader/wsi.h
+++ b/loader/wsi.h
@@ -169,4 +169,9 @@
     VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
 
+VKAPI_ATTR VkResult VKAPI_CALL terminator_vkCreateSharedSwapchainsKHR(
+    VkDevice device, uint32_t swapchainCount,
+    const VkSwapchainCreateInfoKHR *pCreateInfos,
+    const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains);
+
 #endif /* WSI_H */
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index 135faee..3a5c87a 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -492,6 +492,8 @@
     def genVkStructureType(self, typename):
         # Add underscore between lowercase then uppercase
         value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
+        value = value.replace('D3_D12', 'D3D12')
+        value = value.replace('Device_IDProp', 'Device_ID_Prop')
         # Change to uppercase
         value = value.upper()
         # Add STRUCTURE_TYPE_
@@ -796,7 +798,11 @@
             # Need to process all elements in the array
             indexName = lenValue.name.replace('Count', 'Index')
             expr[-1] += '\n'
-            expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < {}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
+            if lenValue.ispointer:
+                # If the length value is a pointer, de-reference it for the count.
+                expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < *{}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
+            else:
+                expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < {}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName))
             expr.append(indent + '{')
             indent = self.incIndent(indent)
             # Prefix for value name to display in error message
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
index 8dfdb7e..05e659f 100644
--- a/scripts/threading_generator.py
+++ b/scripts/threading_generator.py
@@ -400,9 +400,12 @@
             self.appendSection('command', decls[0])
             self.intercepts += [ '    {"%s", reinterpret_cast<PFN_vkVoidFunction>(%s)},' % (name,name[2:]) ]
             return
-        if "KHR" in name:
+        if ("KHR" in name) or ("KHX" in name):
             self.appendSection('command', '// TODO - not wrapping KHR function ' + name)
             return
+        if ("NN" in name):
+            self.appendSection('command', '// TODO - not wrapping NN function ' + name)
+            return
         if ("DebugMarker" in name) and ("EXT" in name):
             self.appendSection('command', '// TODO - not wrapping EXT function ' + name)
             return
diff --git a/scripts/unique_objects_generator.py b/scripts/unique_objects_generator.py
index 46b7d8f..6663df0 100644
--- a/scripts/unique_objects_generator.py
+++ b/scripts/unique_objects_generator.py
@@ -408,30 +408,29 @@
     # Generate source for creating a non-dispatchable object
     def generate_create_ndo_code(self, indent, proto, params, cmd_info):
         create_ndo_code = ''
-        if True in [create_txt in proto.text for create_txt in ['Create', 'Allocate']]:
-            handle_type = params[-1].find('type')
-            if self.isHandleTypeNonDispatchable(handle_type.text):
-                # Check for special case where multiple handles are returned
-                ndo_array = False
-                if cmd_info[-1].len is not None:
-                    ndo_array = True;
-                handle_name = params[-1].find('name')
-                create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
+        handle_type = params[-1].find('type')
+        if self.isHandleTypeNonDispatchable(handle_type.text):
+            # Check for special case where multiple handles are returned
+            ndo_array = False
+            if cmd_info[-1].len is not None:
+                ndo_array = True;
+            handle_name = params[-1].find('name')
+            create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
+            indent = self.incIndent(indent)
+            create_ndo_code += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
+            ndo_dest = '*%s' % handle_name.text
+            if ndo_array == True:
+                create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len)
                 indent = self.incIndent(indent)
-                create_ndo_code += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
-                ndo_dest = '*%s' % handle_name.text
-                if ndo_array == True:
-                    create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len)
-                    indent = self.incIndent(indent)
-                    ndo_dest = '%s[index0]' % cmd_info[-1].name
-                create_ndo_code += '%suint64_t unique_id = global_unique_id++;\n' % (indent)
-                create_ndo_code += '%sdev_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(%s);\n' % (indent, ndo_dest)
-                create_ndo_code += '%s%s = reinterpret_cast<%s&>(unique_id);\n' % (indent, ndo_dest, handle_type.text)
-                if ndo_array == True:
-                    indent = self.decIndent(indent)
-                    create_ndo_code += '%s}\n' % indent
+                ndo_dest = '%s[index0]' % cmd_info[-1].name
+            create_ndo_code += '%suint64_t unique_id = global_unique_id++;\n' % (indent)
+            create_ndo_code += '%sdev_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(%s);\n' % (indent, ndo_dest)
+            create_ndo_code += '%s%s = reinterpret_cast<%s&>(unique_id);\n' % (indent, ndo_dest, handle_type.text)
+            if ndo_array == True:
                 indent = self.decIndent(indent)
-                create_ndo_code += '%s}\n' % (indent)
+                create_ndo_code += '%s}\n' % indent
+            indent = self.decIndent(indent)
+            create_ndo_code += '%s}\n' % (indent)
         return create_ndo_code
     #
     # Generate source for destroying a non-dispatchable object
@@ -685,7 +684,7 @@
                     islocal = True
 
             isdestroy = True if True in [destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free']] else False
-            iscreate = True if True in [create_txt in cmdname for create_txt in ['Create', 'Allocate']] else False
+            iscreate = True if True in [create_txt in cmdname for create_txt in ['Create', 'Allocate', 'GetRandROutputDisplayEXT', 'RegisterDeviceEvent', 'RegisterDisplayEvent']] else False
 
             membersInfo.append(self.CommandParam(type=type,
                                                  name=name,
diff --git a/scripts/vk.xml b/scripts/vk.xml
index 4f358c2..779875b 100644
--- a/scripts/vk.xml
+++ b/scripts/vk.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <registry>
     <comment>
-Copyright (c) 2015-2016 The Khronos Group Inc.
+Copyright (c) 2015-2017 The Khronos Group Inc.
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and/or associated documentation files (the
@@ -62,6 +62,7 @@
         <tag name="SEC"         author="Samsung Electronics Co., Ltd." contact="Alon Or-bach @alonorbach"/>
         <tag name="TIZEN"       author="Samsung Electronics Co., Ltd." contact="Alon Or-bach @alonorbach"/>
         <tag name="RENDERDOC"   author="RenderDoc (renderdoc.org)"     contact="baldurk@baldurk.org"/>
+        <tag name="NN"          author="Nintendo Co., Ltd."            contact="Yasuhiro Yoshioka @yoshioka_yasuhiro"/>
     </tags>
 
     <!-- SECTION: Vulkan type definitions -->
@@ -70,6 +71,7 @@
             <!-- WSI extensions -->
         <type category="include">#include "<name>vulkan.h</name>"</type>
         <type category="include">#include &lt;<name>X11/Xlib.h</name>&gt;</type>
+        <type category="include">#include &lt;<name>X11/extensions/Xrandr.h</name>&gt;</type>
         <type category="include">#include &lt;<name>android/native_window.h</name>&gt;</type>
         <type category="include">#include &lt;<name>mir_toolkit/client_types.h</name>&gt;</type>
         <type category="include">#include &lt;<name>wayland-client.h</name>&gt;</type>
@@ -79,6 +81,7 @@
         <type requires="X11/Xlib.h" name="Display"/>
         <type requires="X11/Xlib.h" name="VisualID"/>
         <type requires="X11/Xlib.h" name="Window"/>
+        <type requires="X11/extensions/Xrandr.h" name="RROutput"/>
         <type requires="android/native_window.h" name="ANativeWindow"/>
         <type requires="mir_toolkit/client_types.h" name="MirConnection"/>
         <type requires="mir_toolkit/client_types.h" name="MirSurface"/>
@@ -104,7 +107,7 @@
         <type category="define">// Vulkan 1.0 version number
 #define <name>VK_API_VERSION_1_0</name> <type>VK_MAKE_VERSION</type>(1, 0, 0)</type>    <!-- The patch version here should never be set to anything other than 0 -->
         <type category="define">// Version of this file
-#define <name>VK_HEADER_VERSION</name> 38</type>
+#define <name>VK_HEADER_VERSION</name> 39</type>
 
         <type category="define">
 #define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
@@ -208,14 +211,17 @@
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkDisplaySurfaceCreateFlagsKHR</name>;</type>     <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkAndroidSurfaceCreateFlagsKHR</name>;</type>     <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkMirSurfaceCreateFlagsKHR</name>;</type>         <!-- creation flags -->
+        <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkViSurfaceCreateFlagsNN</name>;</type>      <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkWaylandSurfaceCreateFlagsKHR</name>;</type>     <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkWin32SurfaceCreateFlagsKHR</name>;</type>       <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkXlibSurfaceCreateFlagsKHR</name>;</type>        <!-- creation flags -->
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkXcbSurfaceCreateFlagsKHR</name>;</type>         <!-- creation flags -->
 
         <type requires="VkDebugReportFlagBitsEXT"      category="bitmask">typedef <type>VkFlags</type> <name>VkDebugReportFlagsEXT</name>;</type>
+        <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkCommandPoolTrimFlagsKHR</name>;</type>
         <type requires="VkExternalMemoryHandleTypeFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryHandleTypeFlagsNV</name>;</type>
         <type requires="VkExternalMemoryFeatureFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryFeatureFlagsNV</name>;</type>
+        <type requires="VkSurfaceCounterFlagBitsEXT"      category="bitmask">typedef <type>VkFlags</type> <name>VkSurfaceCounterFlagsEXT</name>;</type>
 
         <!-- Types which can be void pointers or class pointers, selected at compile time -->
         <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkInstance</name>)</type>
@@ -357,6 +363,10 @@
         <type name="VkExternalMemoryHandleTypeFlagBitsNV" category="enum"/>
         <type name="VkExternalMemoryFeatureFlagBitsNV" category="enum"/>
         <type name="VkValidationCheckEXT" category="enum"/>
+        <type name="VkSurfaceCounterFlagBitsEXT" category="enum"/>
+        <type name="VkDisplayPowerStateEXT" category="enum"/>
+        <type name="VkDeviceEventTypeEXT" category="enum"/>
+        <type name="VkDisplayEventTypeEXT" category="enum"/>
 
         <!-- The PFN_vk*Function types are used by VkAllocationCallbacks below -->
         <type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkInternalAllocationNotification</name>)(
@@ -492,7 +502,7 @@
         </type>
         <type category="struct" name="VkDeviceCreateInfo">
             <member values="VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
-            <member>const <type>void</type>*     <name>pNext</name></member>                          <!-- Pointer to next structure -->
+            <member validextensionstructs="VkPhysicalDeviceFeatures2KHR">const <type>void</type>*     <name>pNext</name></member>                          <!-- Pointer to next structure -->
             <member optional="true"><type>VkDeviceCreateFlags</type>    <name>flags</name></member>                   <!-- Reserved -->
             <member><type>uint32_t</type>        <name>queueCreateInfoCount</name></member>
             <member len="queueCreateInfoCount">const <type>VkDeviceQueueCreateInfo</type>* <name>pQueueCreateInfos</name></member>
@@ -1463,6 +1473,12 @@
             <member noautovalidity="true"><type>MirConnection</type>*                   <name>connection</name></member>
             <member noautovalidity="true"><type>MirSurface</type>*                      <name>mirSurface</name></member>
         </type>
+        <type category="struct" name="VkViSurfaceCreateInfoNN">
+            <member values="VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member optional="true"><type>VkViSurfaceCreateFlagsNN</type>   <name>flags</name></member>        <!-- Reserved -->
+            <member><type>void</type>*                            <name>window</name></member>
+        </type>
         <type category="struct" name="VkWaylandSurfaceCreateInfoKHR">
             <member values="VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
             <member>const <type>void</type>*                      <name>pNext</name></member>                    <!-- Pointer to next structure -->
@@ -1517,7 +1533,7 @@
         </type>
         <type category="struct" name="VkPresentInfoKHR">
             <member values="VK_STRUCTURE_TYPE_PRESENT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
-            <member>const <type>void</type>*                      <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member validextensionstructs="VkDisplayPresentInfoKHR">const <type>void</type>* <name>pNext</name></member>                    <!-- Pointer to next structure -->
             <member optional="true"><type>uint32_t</type>         <name>waitSemaphoreCount</name></member>       <!-- Number of semaphores to wait for before presenting -->
             <member optional="true" len="waitSemaphoreCount">const <type>VkSemaphore</type>* <name>pWaitSemaphores</name></member> <!-- Semaphores to wait for before presenting -->
             <member><type>uint32_t</type>                         <name>swapchainCount</name></member>           <!-- Number of swap chains to present in this call -->
@@ -1713,6 +1729,7 @@
             <member><type>VkObjectEntryTypeNVX</type>         <name>type</name></member>
             <member><type>VkObjectEntryUsageFlagsNVX</type>   <name>flags</name></member>
             <member><type>VkBuffer</type>                     <name>buffer</name></member>
+            <member><type>VkIndexType</type>                  <name>indexType</name></member>
         </type>
         <type category="struct" name="VkObjectTablePushConstantEntryNVX">
             <member><type>VkObjectEntryTypeNVX</type>         <name>type</name></member>
@@ -1720,6 +1737,94 @@
             <member><type>VkPipelineLayout</type>             <name>pipelineLayout</name></member>
             <member><type>VkShaderStageFlags</type>           <name>stageFlags</name></member>
         </type>
+        <type category="struct" name="VkPhysicalDeviceFeatures2KHR">
+            <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkPhysicalDeviceFeatures</type>         <name>features</name></member>
+        </type>
+        <type category="struct" name="VkPhysicalDeviceProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkPhysicalDeviceProperties</type>       <name>properties</name></member>
+        </type>
+        <type category="struct" name="VkFormatProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkFormatProperties</type>               <name>formatProperties</name></member>
+        </type>
+        <type category="struct" name="VkImageFormatProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>* <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkImageFormatProperties</type>          <name>imageFormatProperties</name></member>
+        </type>
+        <type category="struct" name="VkPhysicalDeviceImageFormatInfo2KHR">
+            <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>* <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkFormat</type>                         <name>format</name></member>
+            <member><type>VkImageType</type>                      <name>type</name></member>
+            <member><type>VkImageTiling</type>                    <name>tiling</name></member>
+            <member><type>VkImageUsageFlags</type>                <name>usage</name></member>
+            <member optional="true"><type>VkImageCreateFlags</type> <name>flags</name></member>
+        </type>
+        <type category="struct" name="VkQueueFamilyProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkQueueFamilyProperties</type>          <name>queueFamilyProperties</name></member>
+        </type>
+        <type category="struct" name="VkPhysicalDeviceMemoryProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkPhysicalDeviceMemoryProperties</type> <name>memoryProperties</name></member>
+        </type>
+        <type category="struct" name="VkSparseImageFormatProperties2KHR" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkSparseImageFormatProperties</type>    <name>properties</name></member>
+        </type>
+        <type category="struct" name="VkPhysicalDeviceSparseImageFormatInfo2KHR">
+            <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>                    <!-- Pointer to next structure -->
+            <member><type>VkFormat</type>                         <name>format</name></member>
+            <member><type>VkImageType</type>                      <name>type</name></member>
+            <member><type>VkSampleCountFlagBits</type>            <name>samples</name></member>
+            <member><type>VkImageUsageFlags</type>                <name>usage</name></member>
+            <member><type>VkImageTiling</type>                    <name>tiling</name></member>
+        </type>
+        <type category="struct" name="VkSurfaceCapabilities2EXT" returnedonly="true">
+            <member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>
+            <member><type>uint32_t</type>                         <name>minImageCount</name></member>            <!-- Supported minimum number of images for the surface -->
+            <member><type>uint32_t</type>                         <name>maxImageCount</name></member>            <!-- Supported maximum number of images for the surface, 0 for unlimited -->
+            <member><type>VkExtent2D</type>                       <name>currentExtent</name></member>            <!-- Current image width and height for the surface, (0, 0) if undefined -->
+            <member><type>VkExtent2D</type>                       <name>minImageExtent</name></member>           <!-- Supported minimum image width and height for the surface -->
+            <member><type>VkExtent2D</type>                       <name>maxImageExtent</name></member>           <!-- Supported maximum image width and height for the surface -->
+            <member><type>uint32_t</type>                         <name>maxImageArrayLayers</name></member>      <!-- Supported maximum number of image layers for the surface -->
+            <member optional="true"><type>VkSurfaceTransformFlagsKHR</type>       <name>supportedTransforms</name></member>      <!-- 1 or more bits representing the transforms supported -->
+            <member><type>VkSurfaceTransformFlagBitsKHR</type>    <name>currentTransform</name></member>         <!-- The surface's current transform relative to the device's natural orientation -->
+            <member optional="true"><type>VkCompositeAlphaFlagsKHR</type>         <name>supportedCompositeAlpha</name></member>  <!-- 1 or more bits representing the alpha compositing modes supported -->
+            <member optional="true"><type>VkImageUsageFlags</type>                <name>supportedUsageFlags</name></member>      <!-- Supported image usage flags for the surface -->
+            <member optional="true"><type>VkSurfaceCounterFlagsEXT</type> <name>supportedSurfaceCounters</name></member>
+        </type>
+        <type category="struct" name="VkDisplayPowerInfoEXT">
+            <member values="VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member><type>VkDisplayPowerStateEXT</type>           <name>powerState</name></member>
+        </type>
+        <type category="struct" name="VkDeviceEventInfoEXT">
+            <member values="VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member><type>VkDeviceEventTypeEXT</type>             <name>deviceEvent</name></member>
+        </type>
+        <type category="struct" name="VkDisplayEventInfoEXT">
+            <member values="VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member><type>VkDisplayEventTypeEXT</type>            <name>displayEvent</name></member>
+        </type>
+        <type category="struct" name="VkSwapchainCounterCreateInfoEXT">
+            <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member optional="true"><type>VkSurfaceCounterFlagsEXT</type>         <name>surfaceCounters</name></member>
+        </type>
     </types>
 
     <!-- SECTION: Vulkan enumerant (token) definitions. -->
@@ -2575,6 +2680,21 @@
         <enum value="3" name="VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX"/>
         <enum value="4" name="VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX"/>
     </enums>
+    <enums name="VkSurfaceCounterFlagBitsEXT" type="bitmask">
+        <enum bitpos="0" name="VK_SURFACE_COUNTER_VBLANK_EXT"/>
+    </enums>
+    <enums name="VkDisplayPowerStateEXT" type="enum">
+        <enum value="0" name="VK_DISPLAY_POWER_STATE_OFF_EXT"/>
+        <enum value="1" name="VK_DISPLAY_POWER_STATE_SUSPEND_EXT"/>
+        <enum value="2" name="VK_DISPLAY_POWER_STATE_ON_EXT"/>
+    </enums>
+    <enums name="VkDeviceEventTypeEXT" type="enum">
+        <enum value="0" name="VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT"/>
+    </enums>
+    <enums name="VkDisplayEventTypeEXT" type="enum">
+        <enum value="0" name="VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT"/>
+    </enums>
+
     <!-- SECTION: Vulkan command definitions -->
     <commands>
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_LAYER_NOT_PRESENT,VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INCOMPATIBLE_DRIVER">
@@ -3372,7 +3492,7 @@
             <param><type>VkDeviceSize</type> <name>dataSize</name></param>
             <param len="dataSize">const <type>void</type>* <name>pData</name></param>
         </command>
-        <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" pipeline="transfer">
+        <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" pipeline="transfer" comment="transfer support is only available when VK_KHR_maintenance1 is enabled, as documented in valid usage language in the specification">
             <proto><type>void</type> <name>vkCmdFillBuffer</name></proto>
             <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
             <param><type>VkBuffer</type> <name>dstBuffer</name></param>
@@ -3666,6 +3786,13 @@
             <param externsync="true"><type>VkQueue</type> <name>queue</name></param>
             <param externsync="pPresentInfo.pWaitSemaphores[],pPresentInfo.pSwapchains[]">const <type>VkPresentInfoKHR</type>* <name>pPresentInfo</name></param>
         </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+            <proto><type>VkResult</type> <name>vkCreateViSurfaceNN</name></proto>
+            <param><type>VkInstance</type> <name>instance</name></param>
+            <param>const <type>VkViSurfaceCreateInfoNN</type>* <name>pCreateInfo</name></param>
+            <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+            <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+        </command>
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
             <proto><type>VkResult</type> <name>vkCreateWaylandSurfaceKHR</name></proto>
             <param><type>VkInstance</type> <name>instance</name></param>
@@ -3863,6 +3990,104 @@
             <param><type>VkDeviceGeneratedCommandsFeaturesNVX</type>* <name>pFeatures</name></param>
             <param><type>VkDeviceGeneratedCommandsLimitsNVX</type>* <name>pLimits</name></param>
         </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceFeatures2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkPhysicalDeviceFeatures2KHR</type>* <name>pFeatures</name></param>
+        </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkPhysicalDeviceProperties2KHR</type>* <name>pProperties</name></param>
+        </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceFormatProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkFormat</type> <name>format</name></param>
+            <param><type>VkFormatProperties2KHR</type>* <name>pFormatProperties</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+            <proto><type>VkResult</type> <name>vkGetPhysicalDeviceImageFormatProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param>const <type>VkPhysicalDeviceImageFormatInfo2KHR</type>* <name>pImageFormatInfo</name></param>
+            <param><type>VkImageFormatProperties2KHR</type>* <name>pImageFormatProperties</name></param>
+        </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceQueueFamilyProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param optional="false,true"><type>uint32_t</type>* <name>pQueueFamilyPropertyCount</name></param>
+            <param optional="true" len="pQueueFamilyPropertyCount"><type>VkQueueFamilyProperties2KHR</type>* <name>pQueueFamilyProperties</name></param>
+        </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceMemoryProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkPhysicalDeviceMemoryProperties2KHR</type>* <name>pMemoryProperties</name></param>
+        </command>
+        <command>
+            <proto><type>void</type> <name>vkGetPhysicalDeviceSparseImageFormatProperties2KHR</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param>const <type>VkPhysicalDeviceSparseImageFormatInfo2KHR</type>* <name>pFormatInfo</name></param>
+            <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+            <param optional="true" len="pPropertyCount"><type>VkSparseImageFormatProperties2KHR</type>* <name>pProperties</name></param>
+        </command>
+        <command>
+             <proto><type>void</type> <name>vkTrimCommandPoolKHR</name></proto>
+             <param><type>VkDevice</type> <name>device</name></param>
+             <param externsync="true"><type>VkCommandPool</type> <name>commandPool</name></param>
+             <param optional="true"><type>VkCommandPoolTrimFlagsKHR</type> <name>flags</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkReleaseDisplayEXT</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkDisplayKHR</type> <name>display</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkAcquireXlibDisplayEXT</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>Display</type>* <name>dpy</name></param>
+            <param><type>VkDisplayKHR</type> <name>display</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkGetRandROutputDisplayEXT</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>Display</type>* <name>dpy</name></param>
+            <param><type>RROutput</type> <name>rrOutput</name></param>
+            <param><type>VkDisplayKHR</type>* <name>pDisplay</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkDisplayPowerControlEXT</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkDisplayKHR</type> <name>display</name></param>
+            <param>const <type>VkDisplayPowerInfoEXT</type>* <name>pDisplayPowerInfo</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkRegisterDeviceEventEXT</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param>const <type>VkDeviceEventInfoEXT</type>* <name>pDeviceEventInfo</name></param>
+            <param>const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+            <param><type>VkFence</type>* <name>pFence</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS">
+            <proto><type>VkResult</type> <name>vkRegisterDisplayEventEXT</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkDisplayKHR</type> <name>display</name></param>
+            <param>const <type>VkDisplayEventInfoEXT</type>* <name>pDisplayEventInfo</name></param>
+            <param>const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+            <param><type>VkFence</type>* <name>pFence</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS,VK_ERROR_DEVICE_LOST,VK_ERROR_OUT_OF_DATE_KHR">
+            <proto><type>VkResult</type> <name>vkGetSwapchainCounterEXT</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+            <param><type>VkSurfaceCounterFlagBitsEXT</type> <name>counter</name></param>
+            <param><type>uint64_t</type>* <name>pCounterValue</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+            <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceCapabilities2EXT</name></proto>
+            <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+            <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+            <param><type>VkSurfaceCapabilities2EXT</type>* <name>pSurfaceCapabilities</name></param>
+        </command>
     </commands>
 
     <!-- SECTION: Vulkan API interface definitions -->
@@ -4581,10 +4806,35 @@
                 <type name="VkWin32KeyedMutexAcquireReleaseInfoNV"/>
             </require>
         </extension>
-        <extension name="VK_KHR_extension_60" number="60" author="KHR" contact="Jeff Bolz @jbolz" supported="disabled">
+        <extension name="VK_KHR_get_physical_device_properties2" number="60" author="KHR" contact="Jeff Bolz @jbolz" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_KHR_EXTENSION_60_SPEC_VERSION"/>
-                <enum value="&quot;VK_KHR_extension_60&quot;"           name="VK_KHR_EXTENSION_60_EXTENSION_NAME"/>
+                <enum value="1"                                           name="VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION"/>
+                <enum value="&quot;VK_KHR_get_physical_device_properties2&quot;" name="VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME"/>
+                <enum offset="0" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR"/>
+                <enum offset="1" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR"/>
+                <enum offset="2" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR"/>
+                <enum offset="3" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR"/>
+                <enum offset="4" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR"/>
+                <enum offset="5" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR"/>
+                <enum offset="6" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR"/>
+                <enum offset="7" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR"/>
+                <enum offset="8" extends="VkStructureType"                name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR"/>
+                <type name="VkPhysicalDeviceFeatures2KHR"/>
+                <type name="VkPhysicalDeviceProperties2KHR"/>
+                <type name="VkFormatProperties2KHR"/>
+                <type name="VkImageFormatProperties2KHR"/>
+                <type name="VkPhysicalDeviceImageFormatInfo2KHR"/>
+                <type name="VkQueueFamilyProperties2KHR"/>
+                <type name="VkPhysicalDeviceMemoryProperties2KHR"/>
+                <type name="VkSparseImageFormatProperties2KHR"/>
+                <type name="VkPhysicalDeviceSparseImageFormatInfo2KHR"/>
+                <command name="vkGetPhysicalDeviceFeatures2KHR"/>
+                <command name="vkGetPhysicalDeviceProperties2KHR"/>
+                <command name="vkGetPhysicalDeviceFormatProperties2KHR"/>
+                <command name="vkGetPhysicalDeviceImageFormatProperties2KHR"/>
+                <command name="vkGetPhysicalDeviceQueueFamilyProperties2KHR"/>
+                <command name="vkGetPhysicalDeviceMemoryProperties2KHR"/>
+                <command name="vkGetPhysicalDeviceSparseImageFormatProperties2KHR"/>
             </require>
         </extension>
         <extension name="VK_KHR_extension_61" number="61" author="KHR" contact="Jeff Bolz @jbolz" supported="disabled">
@@ -4601,28 +4851,32 @@
                 <type name="VkValidationFlagsEXT"/>
             </require>
         </extension>
-        <extension name="VK_NV_extension_63" number="63" author="NVIDIA" contact="Mathias Heyer @mheyer" supported="disabled">
+        <extension name="VK_NN_vi_surface" number="63" author="NN" contact="Mathias Heyer @mheyer" type="instance" requires="VK_KHR_surface" protect="VK_USE_PLATFORM_VI_NN" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_NV_EXTENSION_63_SPEC_VERSION"/>
-                <enum value="&quot;VK_NV_extension_63&quot;"            name="VK_NV_EXTENSION_63_EXTENSION_NAME"/>
+                <enum value="1"                                         name="VK_NN_VI_SURFACE_SPEC_VERSION"/>
+                <enum value="&quot;VK_NN_vi_surface&quot;"              name="VK_NN_VI_SURFACE_EXTENSION_NAME"/>
+                <enum offset="0" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN"/>
+                <type name="VkViSurfaceCreateFlagsNN"/>
+                <type name="VkViSurfaceCreateInfoNN"/>
+                <command name="vkCreateViSurfaceNN"/>
             </require>
         </extension>
-        <extension name="VK_KHR_extension_64" number="64" author="KHR" contact="Daniel Koch @dgkoch" supported="disabled">
+        <extension name="VK_KHR_shader_draw_parameters" number="64" type="device" author="KHR" contact="Daniel Koch @dgkoch" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_KHR_EXTENSION_64_SPEC_VERSION"/>
-                <enum value="&quot;VK_KHR_extension_64&quot;"           name="VK_KHR_EXTENSION_64_EXTENSION_NAME"/>
+                <enum value="1"                                         name="VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION"/>
+                <enum value="&quot;VK_KHR_shader_draw_parameters&quot;" name="VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME"/>
             </require>
         </extension>
-        <extension name="VK_NV_extension_65" number="65" author="NVIDIA" contact="Daniel Koch @dgkoch" supported="disabled">
+        <extension name="VK_EXT_shader_subgroup_ballot" number="65" author="NVIDIA" contact="Daniel Koch @dgkoch" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_NV_EXTENSION_65_SPEC_VERSION"/>
-                <enum value="&quot;VK_NV_extension_65&quot;"            name="VK_NV_EXTENSION_65_EXTENSION_NAME"/>
+                <enum value="1"                                         name="VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION"/>
+                <enum value="&quot;VK_EXT_shader_subgroup_ballot&quot;" name="VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME"/>
             </require>
         </extension>
-        <extension name="VK_NV_extension_66" number="66" author="NVIDIA" contact="Daniel Koch @dgkoch" supported="disabled">
+        <extension name="VK_EXT_shader_subgroup_vote" number="66" author="NVIDIA" contact="Daniel Koch @dgkoch" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_NV_EXTENSION_66_SPEC_VERSION"/>
-                <enum value="&quot;VK_NV_extension_66&quot;"            name="VK_NV_EXTENSION_66_EXTENSION_NAME"/>
+                <enum value="1"                                         name="VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION"/>
+                <enum value="&quot;VK_EXT_shader_subgroup_vote&quot;"   name="VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME"/>
             </require>
         </extension>
         <extension name="VK_ARM_extension_01" number="67" type="device" author="ARM" contact="Jan-Harald Fredriksen @janharald" supported="disabled">
@@ -4643,10 +4897,15 @@
                 <enum value="&quot;VK_IMG_extension_69&quot;"           name="VK_IMG_EXTENSION_69_EXTENSION_NAME"/>
             </require>
         </extension>
-        <extension name="VK_KHR_extension_70" number="70" author="KHR" contact="Piers Daniell @pdaniell" supported="disabled">
+        <extension name="VK_KHR_maintenance1" number="70" author="KHR" contact="Piers Daniell @pdaniell" supported="vulkan">
             <require>
-                <enum value="0"                                         name="VK_KHR_EXTENSION_70_SPEC_VERSION"/>
-                <enum value="&quot;VK_KHR_extension_70&quot;"           name="VK_KHR_EXTENSION_70_EXTENSION_NAME"/>
+                <enum value="1"                                         name="VK_KHR_MAINTENANCE1_SPEC_VERSION"/>
+                <enum value="&quot;VK_KHR_maintenance1&quot;"           name="VK_KHR_MAINTENANCE1_EXTENSION_NAME"/>
+                <enum offset="0" dir="-" extends="VkResult"             name="VK_ERROR_OUT_OF_POOL_MEMORY_KHR"/>
+                <enum bitpos="14" extends="VkFormatFeatureFlagBits"     name="VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR" comment="Format can be used as the source image of image transfer commands"/>
+                <enum bitpos="15" extends="VkFormatFeatureFlagBits"     name="VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR" comment="Format can be used as the destination image of image transfer commands"/>
+                <enum bitpos="5" extends="VkImageCreateFlagBits"        name="VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR" comment="The 3D image can be viewed as a 2D or 2D array image"/>
+                <command name="vkTrimCommandPoolKHR"/>
             </require>
         </extension>
         <extension name="VK_KHR_extension_71" number="71" author="KHR" contact="Jeff Bolz @jbolz" supported="disabled">
@@ -4797,29 +5056,52 @@
                  <enum value="&quot;VK_KHR_extension_88&quot;"           name="VK_KHR_EXTENSION_88_EXTENSION_NAME"/>
               </require>
          </extension>
-         <extension name="VK_EXT_extension_89" number="89" author="NV" contact="James Jones @cubanismo" supported="disabled">
+         <extension name="VK_EXT_direct_mode_display" number="89" type="instance" requires="VK_KHR_display" author="NVIDIA" contact="James Jones @cubanismo" supported="vulkan">
              <require>
-                 <enum value="0"                                         name="VK_EXT_EXTENSION_89_SPEC_VERSION"/>
-                 <enum value="&quot;VK_EXT_extension_89&quot;"           name="VK_EXT_EXTENSION_89_EXTENSION_NAME"/>
-              </require>
+                 <enum value="1"                                         name="VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_direct_mode_display&quot;"           name="VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME"/>
+                 <command name="vkReleaseDisplayEXT"/>
+             </require>
          </extension>
-         <extension name="VK_EXT_extension_90" number="90" author="NV" contact="James Jones @cubanismo" supported="disabled">
+         <extension name="VK_EXT_acquire_xlib_display" number="90" type="instance" requires="VK_EXT_direct_mode_display,VK_KHR_display" author="NVIDIA" contact="James Jones @cubanismo" protect="VK_USE_PLATFORM_XLIB_XRANDR_EXT" supported="vulkan">
              <require>
-                 <enum value="0"                                         name="VK_EXT_EXTENSION_90_SPEC_VERSION"/>
-                 <enum value="&quot;VK_EXT_extension_90&quot;"           name="VK_EXT_EXTENSION_90_EXTENSION_NAME"/>
-              </require>
+                 <enum value="1"                                         name="VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_acquire_xlib_display&quot;"   name="VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME"/>
+                 <command name="vkAcquireXlibDisplayEXT"/>
+                 <command name="vkGetRandROutputDisplayEXT"/>
+             </require>
          </extension>
-         <extension name="VK_EXT_extension_91" number="91" author="NV" contact="James Jones @cubanismo" supported="disabled">
+         <extension name="VK_EXT_display_surface_counter" number="91" type="instance" requires="VK_KHR_display" author="NVIDIA" contact="James Jones @cubanismo" supported="vulkan">
              <require>
-                 <enum value="0"                                         name="VK_EXT_EXTENSION_91_SPEC_VERSION"/>
-                 <enum value="&quot;VK_EXT_extension_91&quot;"           name="VK_EXT_EXTENSION_91_EXTENSION_NAME"/>
-              </require>
+                 <enum value="1"                                         name="VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_display_surface_counter&quot;" name="VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME"/>
+                 <enum offset="0" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT"/>
+                 <type name="VkSurfaceCounterFlagsEXT"/>
+                 <type name="VkSurfaceCounterFlagBitsEXT"/>
+                 <type name="VkSurfaceCapabilities2EXT"/>
+                 <command name="vkGetPhysicalDeviceSurfaceCapabilities2EXT"/>
+             </require>
          </extension>
-         <extension name="VK_EXT_extension_92" number="92" author="NV" contact="James Jones @cubanismo" supported="disabled">
+         <extension name="VK_EXT_display_control" number="92" type="device" requires="VK_KHR_display,VK_EXT_display_surface_counter,VK_KHR_swapchain" author="NVIDIA" contact="James Jones @cubanismo" supported="vulkan">
              <require>
-                 <enum value="0"                                         name="VK_EXT_EXTENSION_92_SPEC_VERSION"/>
-                 <enum value="&quot;VK_EXT_extension_92&quot;"           name="VK_EXT_EXTENSION_92_EXTENSION_NAME"/>
-              </require>
+                 <enum value="1"                                         name="VK_EXT_DISPLAY_CONTROL_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_display_control&quot;"        name="VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME"/>
+                 <enum offset="0" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT"/>
+                 <enum offset="1" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT"/>
+                 <enum offset="2" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT"/>
+                 <enum offset="3" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT"/>
+                 <type name="VkDisplayPowerStateEXT"/>
+                 <type name="VkDeviceEventTypeEXT"/>
+                 <type name="VkDisplayEventTypeEXT"/>
+                 <type name="VkDisplayPowerInfoEXT"/>
+                 <type name="VkDeviceEventInfoEXT"/>
+                 <type name="VkDisplayEventInfoEXT"/>
+                 <type name="VkSwapchainCounterCreateInfoEXT"/>
+                 <command name="vkDisplayPowerControlEXT"/>
+                 <command name="vkRegisterDeviceEventEXT"/>
+                 <command name="vkRegisterDisplayEventEXT"/>
+                 <command name="vkGetSwapchainCounterEXT"/>
+             </require>
          </extension>
          <extension name="VK_KHR_extension_93" number="93" author="GOOGLE" contact="Ian Elliott @ianelliott" supported="disabled">
              <require>
@@ -4893,10 +5175,94 @@
                  <enum value="&quot;VK_NV_extension_104&quot;"           name="VK_NV_EXTENSION_104_EXTENSION_NAME"/>
              </require>
          </extension>
-         <extension name="VK_EXT_extension_105" number="105" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtneygo" supported="disabled">
+         <extension name="VK_EXT_swapchain_colorspace" number="105" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtneygo" requires="VK_KHR_surface" supported="vulkan">
              <require>
-                 <enum value="0"                                         name="VK_KHR_EXTENSION_105_SPEC_VERSION"/>
-                 <enum value="&quot;VK_EXT_extension_105&quot;"           name="VK_KHR_EXTENSION_105_EXTENSION_NAME"/>
+                 <enum value="1"                                         name="VK_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_swapchain_colorspace&quot;"   name="VK_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME"/>
+                 <enum offset="1" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT"/>
+                 <enum offset="2" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT"/>
+                 <enum offset="3" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_SCRGB_LINEAR_EXT"/>
+                 <enum offset="4" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT"/>
+                 <enum offset="5" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_DCI_P3_LINEAR_EXT"/>
+                 <enum offset="6" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT"/>
+                 <enum offset="7" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_BT709_LINEAR_EXT"/>
+                 <enum offset="8" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_BT709_NONLINEAR_EXT"/>
+                 <enum offset="9" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_BT2020_LINEAR_EXT"/>
+                 <enum offset="10" extends="VkColorSpaceKHR"              name="VK_COLOR_SPACE_BT2020_NONLINEAR_EXT"/>
+                 <enum offset="11" extends="VkColorSpaceKHR"             name="VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT"/>
+                 <enum offset="12" extends="VkColorSpaceKHR"             name="VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT"/>
+             </require>
+         </extension>
+         <extension name="VK_EXT_extension_106" number="106" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtneygo" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_106_SPEC_VERSION"/>
+                 <enum value="&quot;VK_EXT_extension_106&quot;"           name="VK_KHR_EXTENSION_106_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_IMG_extension_107" number="107" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_IMG_EXTENSION_107_SPEC_VERSION"/>
+                 <enum value="&quot;VK_IMG_extension_107&quot;"           name="VK_IMG_EXTENSION_107_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_IMG_extension_108" number="108" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_IMG_EXTENSION_108_SPEC_VERSION"/>
+                 <enum value="&quot;VK_IMG_extension_108&quot;"           name="VK_IMG_EXTENSION_108_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_IMG_extension_109" number="109" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_IMG_EXTENSION_109_SPEC_VERSION"/>
+                 <enum value="&quot;VK_IMG_extension_109&quot;"           name="VK_IMG_EXTENSION_109_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_IMG_extension_110" number="110" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_IMG_EXTENSION_110_SPEC_VERSION"/>
+                 <enum value="&quot;VK_IMG_extension_110&quot;"           name="VK_IMG_EXTENSION_110_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_IMG_extension_111" number="111" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_IMG_EXTENSION_111_SPEC_VERSION"/>
+                 <enum value="&quot;VK_IMG_extension_111&quot;"           name="VK_IMG_EXTENSION_111_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_112" number="112" author="KHR" contact="Alon Or-bach @alonorbach" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_112_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_112&quot;"           name="VK_KHR_EXTENSION_112_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_113" number="113" author="KHX" contact="Cass Everitt @casseveritt" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_113_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_113&quot;"           name="VK_KHR_EXTENSION_113_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_114" number="114" author="KHX" contact="Cass Everitt @casseveritt" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_114_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_114&quot;"           name="VK_KHR_EXTENSION_114_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_115" number="115" author="KHX" contact="Cass Everitt @casseveritt" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_115_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_115&quot;"           name="VK_KHR_EXTENSION_115_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_116" number="116" author="KHX" contact="Cass Everitt @casseveritt" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_116_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_116&quot;"           name="VK_KHR_EXTENSION_116_EXTENSION_NAME"/>
+             </require>
+         </extension>
+         <extension name="VK_KHR_extension_117" number="117" author="KHR" contact="Kenneth Benzie @kbenzie" supported="disabled">
+             <require>
+                 <enum value="0"                                         name="VK_KHR_EXTENSION_117_SPEC_VERSION"/>
+                 <enum value="&quot;VK_KHR_extension_117&quot;"           name="VK_KHR_EXTENSION_117_EXTENSION_NAME"/>
              </require>
          </extension>
     </extensions>
diff --git a/tests/layers/test.cpp b/tests/layers/test.cpp
index 11f79cb..d5e9d5b 100644
--- a/tests/layers/test.cpp
+++ b/tests/layers/test.cpp
@@ -35,6 +35,8 @@
     layer_data() : instance(VK_NULL_HANDLE), instance_dispatch_table(nullptr) {};
 };
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 static std::unordered_map<void *, layer_data *> layer_data_map;
 
 VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
@@ -64,7 +66,6 @@
     instance_data->instance = *pInstance;
     instance_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
     layer_init_instance_dispatch_table(*pInstance, instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
-
     // Marker for testing.
     std::cout << "VK_LAYER_LUNARG_test: CreateInstance" << '\n';
 
@@ -117,6 +118,19 @@
     return pTable->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkLayerInstanceDispatchTable *pTable = instance_data->instance_dispatch_table;
+    if (pTable->GetPhysicalDeviceProcAddr == nullptr)
+    {
+        return nullptr;
+    }
+
+    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 }
 
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
@@ -138,3 +152,27 @@
 {
     return VK_ERROR_LAYER_NOT_PRESENT;
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return test::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        test::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}
diff --git a/tests/layers/wrap_objects.cpp b/tests/layers/wrap_objects.cpp
index f0de3c4..e311ac9 100644
--- a/tests/layers/wrap_objects.cpp
+++ b/tests/layers/wrap_objects.cpp
@@ -34,6 +34,8 @@
     "VK_LAYER_LUNARG_wrap_objects", VK_LAYER_API_VERSION, 1, "LunarG Test Layer",
 };
 
+static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+
 //TODO Add wrapping of Vkdevice, Vkqueue, VkcommandBuffer
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
@@ -1565,6 +1567,18 @@
     return pTable->GetInstanceProcAddr(instance, funcName);
 }
 
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    assert(instance);
+
+    wrapped_inst_obj *inst;
+    (void)unwrap_instance(instance, &inst);
+    VkLayerInstanceDispatchTable* pTable = &inst->layer_disp;
+
+    if (pTable->GetPhysicalDeviceProcAddr == NULL)
+        return NULL;
+    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
 } // namespace wrap_objects
 
 // loader-layer interface v0, just wrappers since there is only a layer
@@ -1602,3 +1616,27 @@
     assert(physicalDevice == VK_NULL_HANDLE);
     return wrap_objects::vkEnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
 }
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    return wrap_objects::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        wrap_objects::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
+    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
+        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
+    }
+
+    return VK_SUCCESS;
+}