[vulkan] Merge in tag sdk-1.2.148.1

Bug: 60761

Change-Id: Ie25f788a7d66a42a207affd86b9418a14681e36c
diff --git a/.appveyor.yml b/.appveyor.yml
index 5146891..afa5e49 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -14,9 +14,6 @@
 os:
   - Visual Studio 2015
 
-init:
-  - git config --global core.autocrlf true
-
 environment:
   PYTHON_PATH: "C:/Python35"
   PYTHON_PACKAGE_PATH: "C:/Python35/Scripts"
diff --git a/.gitattributes b/.gitattributes
index ca85b46..ad66eb7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -5,6 +5,7 @@
 * text=auto
 
 # Files to be converted to native line endings on checkout.
+*.c text
 *.cpp text
 *.h text
 
@@ -14,3 +15,6 @@
 # Text files to always have LF (unix) line endings on checkout.
 *.sh text eol=lf
 
+# Generated source files will always have LF (unix) line endings on checkout.
+loader/generated/*.c text eol=lf
+loader/generated/*.h text eol=lf
diff --git a/BUILD.gn b/BUILD.gn
index dbd9736..7c4abf7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -167,6 +167,15 @@
       runtime_deps = [ "//sdk/lib/fdio:fdio_sdk" ]
     }
   }
+
+  if (is_linux && vulkan_loader_shared) {
+    copy("libvulkan-abi1") {
+      sources = [ "${root_out_dir}/libvulkan.so" ]
+      outputs = [ "${root_out_dir}/libvulkan.so.1" ]
+
+      deps = [ ":libvulkan" ]
+    }
+  }
 }
 
 if (is_fuchsia) {
diff --git a/BUILD.md b/BUILD.md
index 5fc7075..8928936 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -179,6 +179,7 @@
 | BUILD_WSI_XCB_SUPPORT | Linux | `ON` | Build the loader with the XCB entry points enabled. Without this, the XCB headers should not be needed, but the extension `VK_KHR_xcb_surface` won't be available. |
 | BUILD_WSI_XLIB_SUPPORT | Linux | `ON` | Build the loader with the Xlib entry points enabled. Without this, the X11 headers should not be needed, but the extension `VK_KHR_xlib_surface` won't be available. |
 | BUILD_WSI_WAYLAND_SUPPORT | Linux | `ON` | Build the loader with the Wayland entry points enabled. Without this, the Wayland headers should not be needed, but the extension `VK_KHR_wayland_surface` won't be available. |
+| BUILD_WSI_DIRECTFB_SUPPORT | Linux | `OFF` | Build the loader with the DirectFB entry points enabled. Without this, the DirectFB headers should not be needed, but the extension `VK_EXT_directfb_surface` won't be available. |
 | ENABLE_STATIC_LOADER | Windows | `OFF` | By default, the loader is built as a dynamic library. This allows it to be built as a static library, instead. |
 | ENABLE_WIN10_ONECORE | Windows | `OFF` | Link the loader to the [OneCore](https://msdn.microsoft.com/en-us/library/windows/desktop/mt654039.aspx) umbrella library, instead of the standard Win32 ones. |
 | USE_CCACHE | Linux | `OFF` | Enable caching with the CCache program. |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44666ad..a833a03 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,8 +38,14 @@
     option(BUILD_TESTS "Build Tests" OFF)
 endif()
 
-# Add the externals directory early so we pickup the headers if they're present
-add_subdirectory(external)
+if(APPLE)
+    option(BUILD_STATIC_LOADER "Build a loader that can be statically linked" OFF)
+endif()
+
+if(BUILD_STATIC_LOADER)
+    message(WARNING "The ENABLE_STATIC_LOADER option has been set. Note that this will only work on MacOS and is not supported "
+        "or tested as part of the loader. Use it at your own risk.")
+endif()
 
 if (TARGET Vulkan::Headers)
     message(STATUS "Using Vulkan headers from Vulkan::Headers target")
@@ -58,7 +64,7 @@
 
     # set up the Vulkan::Headers target for consistency
     add_library(vulkan-headers INTERFACE)
-    target_include_directories(vulkan-headers INTERFACE "${VulkanHeaders_INCLUDE_DIRS}")
+    target_include_directories(vulkan-headers SYSTEM INTERFACE "${VulkanHeaders_INCLUDE_DIRS}")
     add_library(Vulkan::Headers ALIAS vulkan-headers)
 endif()
 
@@ -115,6 +121,7 @@
     option(BUILD_WSI_XCB_SUPPORT "Build XCB WSI support" ON)
     option(BUILD_WSI_XLIB_SUPPORT "Build Xlib WSI support" ON)
     option(BUILD_WSI_WAYLAND_SUPPORT "Build Wayland WSI support" ON)
+    option(BUILD_WSI_DIRECTFB_SUPPORT "Build DirectFB WSI support" OFF)
 
     if(BUILD_WSI_XCB_SUPPORT)
         find_package(XCB REQUIRED)
@@ -126,7 +133,12 @@
 
     if(BUILD_WSI_WAYLAND_SUPPORT)
         find_package(Wayland REQUIRED)
-        include_directories(${WAYLAND_CLIENT_INCLUDE_DIR})
+        include_directories(SYSTEM ${WAYLAND_CLIENT_INCLUDE_DIR})
+    endif()
+
+    if(BUILD_WSI_DIRECTFB_SUPPORT)
+        find_package(DirectFB REQUIRED)
+        include_directories(SYSTEM ${DIRECTFB_INCLUDE_DIR})
     endif()
 endif()
 
@@ -220,6 +232,7 @@
     add_subdirectory(loader)
 endif()
 
+add_subdirectory(external)
 if(BUILD_TESTS)
     add_subdirectory(tests)
 endif()
diff --git a/build-gn/DEPS b/build-gn/DEPS
index 81cca43..d44f2a3 100644
--- a/build-gn/DEPS
+++ b/build-gn/DEPS
@@ -4,20 +4,20 @@
 
 deps = {
 
-  './build': {
-    'url': '{chromium_git}/chromium/src/build.git@a660b0b9174e3a808f620222017566e8d1b2669b',
+  'build': {
+    'url': '{chromium_git}/chromium/src/build.git@45ab3c89af6fc3126b0ca5a7836f0db85ad1ba0e',
   },
 
-  './buildtools': {
-    'url': '{chromium_git}/chromium/src/buildtools.git@459baaf66bee809f6eb288e0215cf524f4d2429a',
+  'buildtools': {
+    'url': '{chromium_git}/chromium/src/buildtools.git@204a35a2a64f7179f8b76d7a0385653690839e21',
   },
 
-  './testing': {
-    'url': '{chromium_git}/chromium/src/testing@083d633e752e7a57cbe62a468a06e51e28c49ee9',
+  'testing': {
+    'url': '{chromium_git}/chromium/src/testing@3993ef1f527b206d8d3bf3f9824f4fe0e4bbdb0e',
   },
 
-  './tools/clang': {
-    'url': '{chromium_git}/chromium/src/tools/clang.git@3114fbc11f9644c54dd0a4cdbfa867bac50ff983',
+  'tools/clang': {
+    'url': '{chromium_git}/chromium/src/tools/clang.git@04b99e7bf9160d551c3a5562f583014b6afc90f9',
   },
 
 }
@@ -33,25 +33,25 @@
                 '--platform=linux*',
                 '--no_auth',
                 '--bucket', 'chromium-clang-format',
-                '-s', './buildtools/linux64/clang-format.sha1',
+                '-s', 'buildtools/linux64/clang-format.sha1',
     ],
   },
   {
     'name': 'sysroot_x64',
     'pattern': '.',
     'condition': 'checkout_linux and checkout_x64',
-    'action': ['python', './build/linux/sysroot_scripts/install-sysroot.py',
+    'action': ['python', 'build/linux/sysroot_scripts/install-sysroot.py',
                '--arch=x64'],
   },
   {
     # Note: On Win, this should run after win_toolchain, as it may use it.
     'name': 'clang',
     'pattern': '.',
-    'action': ['python', './tools/clang/scripts/update.py'],
+    'action': ['python', 'tools/clang/scripts/update.py'],
   },
 ]
 
 recursedeps = [
   # buildtools provides clang_format.
-  './buildtools',
+  'buildtools',
 ]
diff --git a/cmake/FindDirectFB.cmake b/cmake/FindDirectFB.cmake
new file mode 100644
index 0000000..2c98b2a
--- /dev/null
+++ b/cmake/FindDirectFB.cmake
@@ -0,0 +1,28 @@
+# Try to find DirectFB
+#
+# This will define:
+#
+#   DIRECTFB_FOUND       - True if DirectFB is found
+#   DIRECTFB_LIBRARIES   - Link these to use DirectFB
+#   DIRECTFB_INCLUDE_DIR - Include directory for DirectFB
+#   DIRECTFB_DEFINITIONS - Compiler flags for using DirectFB
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT WIN32)
+  FIND_PACKAGE(PkgConfig)
+  PKG_CHECK_MODULES(PKG_DIRECTFB QUIET directfb)
+
+  SET(DIRECTFB_DEFINITIONS ${PKG_DIRECTFB_CFLAGS})
+
+  FIND_PATH(DIRECTFB_INCLUDE_DIR  NAMES directfb.h HINTS ${PKG_DIRECTFB_INCLUDE_DIRS})
+
+  FIND_LIBRARY(DIRECTFB_LIBRARIES NAMES directfb   HINTS ${PKG_DIRECTFB_LIBRARY_DIRS})
+
+  include(FindPackageHandleStandardArgs)
+
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(DIRECTFB DEFAULT_MSG DIRECTFB_LIBRARIES DIRECTFB_INCLUDE_DIR)
+
+  MARK_AS_ADVANCED(DIRECTFB_INCLUDE_DIR DIRECTFB_LIBRARIES)
+ENDIF ()
diff --git a/cmake/FindVulkanHeaders.cmake b/cmake/FindVulkanHeaders.cmake
index 71b2aff..db3d40e 100644
--- a/cmake/FindVulkanHeaders.cmake
+++ b/cmake/FindVulkanHeaders.cmake
@@ -74,9 +74,10 @@
 else()
   # If VULKAN_HEADERS_INSTALL_DIR, or one of its variants was not specified,
   # do a normal search without hints.
-  find_path(VulkanHeaders_INCLUDE_DIR NAMES vulkan/vulkan.h)
+  find_path(VulkanHeaders_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS "${CMAKE_CURRENT_SOURCE_DIR}/external/Vulkan-Headers/include")
   get_filename_component(VULKAN_REGISTRY_PATH_HINT ${VulkanHeaders_INCLUDE_DIR} DIRECTORY)
-  find_path(VulkanRegistry_DIR NAMES vk.xml HINTS ${VULKAN_REGISTRY_PATH_HINT}/share/vulkan/registry)
+  find_path(VulkanRegistry_DIR NAMES vk.xml HINTS ${VULKAN_REGISTRY_PATH_HINT}/share/vulkan/registry
+    "${VULKAN_REGISTRY_PATH_HINT}/registry")
 endif()
 
 set(VulkanHeaders_INCLUDE_DIRS ${VulkanHeaders_INCLUDE_DIR})
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 2bc27ef..964d098 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -37,7 +37,3 @@
                            "Provide Google Test in external/googletest or set BUILD_TESTS=OFF")
     endif()
 endif()
-
-if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Vulkan-Headers")
-  add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Vulkan-Headers")
-endif()
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index 13a36a2..d0541b1 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -53,6 +53,10 @@
     if(BUILD_WSI_WAYLAND_SUPPORT)
         set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS VK_USE_PLATFORM_WAYLAND_KHR)
     endif()
+
+    if(BUILD_WSI_DIRECTFB_SUPPORT)
+        set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS VK_USE_PLATFORM_DIRECTFB_EXT)
+    endif()
 else()
     message(FATAL_ERROR "Unsupported Platform!")
 endif()
@@ -170,6 +174,7 @@
         target_link_libraries(asm_offset Vulkan::Headers)
         add_custom_command(OUTPUT gen_defines.asm DEPENDS asm_offset COMMAND asm_offset GAS)
         add_custom_target(loader_asm_gen_files DEPENDS gen_defines.asm)
+        target_compile_definitions(asm_offset PRIVATE _XOPEN_SOURCE=500) # hush compiler warnings for readlink
     else()
         message(WARNING "Could not find working x86 GAS assembler\n${ASM_FAILURE_MSG}")
         set(OPT_LOADER_SRCS ${OPT_LOADER_SRCS} unknown_ext_chain.c)
@@ -178,7 +183,7 @@
 endif()
 
 if(WIN32)
-    add_library(loader-norm OBJECT ${NORMAL_LOADER_SRCS} dirent_on_windows.c dxgi_loader.c)
+    add_library(loader-norm OBJECT ${NORMAL_LOADER_SRCS} dirent_on_windows.c)
     target_compile_options(loader-norm PUBLIC "$<$<CONFIG:DEBUG>:${LOCAL_C_FLAGS_DBG}>")
     target_compile_options(loader-norm PUBLIC ${MSVC_LOADER_COMPILE_OPTIONS})
     target_include_directories(loader-norm PRIVATE "$<TARGET_PROPERTY:Vulkan::Headers,INTERFACE_INCLUDE_DIRECTORIES>")
@@ -222,7 +227,11 @@
         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-typedef-redefinition")
     endif()
 
-    add_library(vulkan SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS})
+    if(APPLE AND BUILD_STATIC_LOADER)
+        add_library(vulkan STATIC ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS})
+    else()
+        add_library(vulkan SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS})
+    endif()
     add_dependencies(vulkan loader_asm_gen_files)
     set_target_properties(vulkan
                           PROPERTIES SOVERSION
@@ -231,7 +240,6 @@
                                      "${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}")
     target_link_libraries(vulkan ${CMAKE_DL_LIBS} pthread m)
     target_link_libraries(vulkan Vulkan::Headers)
-
     if(APPLE)
         find_library(COREFOUNDATION_LIBRARY NAMES CoreFoundation)
         target_link_libraries(vulkan "-framework CoreFoundation")
@@ -254,7 +262,11 @@
             ${VulkanHeaders_INCLUDE_DIRS}/vulkan/vulkan_xlib_xrandr.h
             ${VulkanHeaders_INCLUDE_DIRS}/vulkan/vulkan.h
             ${VulkanHeaders_INCLUDE_DIRS}/vulkan/vulkan.hpp)
-        add_library(vulkan-framework SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS} ${FRAMEWORK_HEADERS})
+        if(BUILD_STATIC_LOADER)
+            add_library(vulkan-framework STATIC ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS} ${FRAMEWORK_HEADERS})
+        else()
+            add_library(vulkan-framework SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS} ${FRAMEWORK_HEADERS})
+        endif()
         add_dependencies(vulkan-framework loader_asm_gen_files)
         target_link_libraries(vulkan-framework -ldl -lpthread -lm "-framework CoreFoundation")
         target_link_libraries(vulkan-framework Vulkan::Headers)
@@ -282,6 +294,8 @@
     endif()
 
     if(NOT APPLE)
+        target_compile_definitions(vulkan PRIVATE _XOPEN_SOURCE=500) # hush compiler warnings for readlink
+
         # Generate pkg-config file.
         include(FindPkgConfig QUIET)
         if(PKG_CONFIG_FOUND)
diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md
index def66d3..c41cd21 100644
--- a/loader/LoaderAndLayerInterface.md
+++ b/loader/LoaderAndLayerInterface.md
@@ -49,13 +49,14 @@
     * [ICD Vulkan Entry Point Discovery](#icd-vulkan-entry-point-discovery)
     * [ICD API Version](#icd-api-version)
     * [ICD Unknown Physical Device Extensions](#icd-unknown-physical-device-extensions)
+    * [Physical Device Sorting](#physical-device-sorting)
     * [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)
 
   * [Table of Debug Environment Variables](#table-of-debug-environment-variables)
   * [Glossary of Terms](#glossary-of-terms)
- 
+
 ## Overview
 
 Vulkan is a layered architecture, made up of the following elements:
@@ -191,7 +192,7 @@
  * `vkBeginCommandBuffer`
  * `vkCreateEvent`
 
-You can query Vulkan Device functions using either `vkGetInstanceProcAddr` or 
+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
@@ -268,7 +269,7 @@
 
 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. 
+*terminator* of the chain.
 
 ![Loader Device Call Chain](./images/loader_device_chain_loader.png)
 
@@ -298,7 +299,7 @@
     * [WSI Extensions](#wsi-extensions)
     * [Unknown Extensions](#unknown-extensions)
 
-  
+
 #### Interfacing with Vulkan Functions
 There are several ways you can interface with Vulkan functions through the
 loader.
@@ -369,7 +370,7 @@
 
 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 
+high-level construct used to provide Vulkan system-level
 information](#instance-related-objects).
 Because of this, Instance functions need to be broadcast to
 every available ICD on the system.  The following diagram shows an approximate
@@ -521,8 +522,8 @@
 ##### Implicit vs Explicit Layers
 
 Explicit layers are layers which are enabled by an application (e.g. with the
-vkCreateInstance function), or by an environment variable (as mentioned
-previously).
+vkCreateInstance function as mentioned previously), or by an environment
+variable.
 
 Implicit layers are those which are enabled by their existence. For example,
 certain application environments (e.g. Steam or an automotive infotainment
@@ -692,7 +693,7 @@
 - VK_KHR_swapchain
 - VK_KHR_display
 
-In addition, each of the following OS targets for the loader support 
+In addition, each of the following OS targets for the loader support
 target-specific extensions:
 
 | Windowing System | Extensions available |
@@ -798,9 +799,9 @@
     * [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)
-  
 
- 
+
+
 #### Layer Discovery
 
 As mentioned in the
@@ -1037,15 +1038,43 @@
 
 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
+“VkNegotiateLayerInterface”.
+
+This function allows the loader and layer to agree on an interface version to use.
+The "loaderLayerInterfaceVersion" field is both an input and output parameter.
+"loaderLayerInterfaceVersion" is filled in by the loader with the desired latest
+interface version supported by the loader (typically the latest). The layer receives
+this and returns back the version it desires in the same field.  Because it is
+setting up the interface version between the loader and layer, this should be
+the first call made by a loader to the layer (even prior to any calls to
+`vkGetInstanceProcAddr`).
+
+If the layer receiving the call no longer supports the interface version provided
+by the loader (due to deprecation), then it should report a
+VK_ERROR_INITIALIZATION_FAILED error.  Otherwise it sets the value pointed by
+"loaderLayerInterfaceVersion" to the latest interface version supported by both the
+layer and the loader and returns VK_SUCCESS.
+
+The layer should report VK_SUCCESS in case the loader-provided interface version
+is newer than that supported by the layer, as it's the loader's responsibility to
+determine whether it can support the older interface version supported by the
+layer.  The layer should also report VK_SUCCESS in the case its interface version
+is greater than the loader's, but return the loader's version. Thus, upon
+return of VK_SUCCESS the "loaderLayerInterfaceVersion" will contain the desired
+interface version to be used by the layer.
+
+If the loader  receives a VK_ERROR_INITIALIZATION_FAILED error instead of
+VK_SUCCESS, then the loader will treat the layer as unusable and will not load
+it for use.  In this case, the application will not see the layer during
+enumeration. Note that the loader is currently backwards compatible with all
+layer interface versions, so a layer should not be able to request a version
+older than what the loader supports.
+
+This function **SHOULD NOT CALL DOWN** the layer chain to the next layer.
+The loader will work with each layer individually.
+
+If the layer supports the new interface and reports version 2 or greater, then
+The layer should fill in the function pointer values to its internal
 functions:
     - "pfnGetInstanceProcAddr" should be set to the layer’s internal
 `GetInstanceProcAddr` function.
@@ -1056,12 +1085,6 @@
       - 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"
-
-This function **SHOULD NOT CALL DOWN** the layer chain to the next layer.
-The loader will work with each layer individually.
-
-If the layer supports the new interface and reports version 2 or greater, then
 the 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"
@@ -1410,7 +1433,7 @@
 #### Example Code for CreateDevice
 
 ```cpp
-VkResult 
+VkResult
 vkCreateDevice(
         VkPhysicalDevice gpu,
         const VkDeviceCreateInfo *pCreateInfo,
@@ -1467,7 +1490,7 @@
  4. The loader will automatically collate all instance and device extensions in
 a meta-layer's component layers, and report them as the meta-layer's properties
 to the application when queried.
- 
+
 Restrictions to defining and using a meta-layer are:
  1. A Meta-layer Manifest file **must** be a properly formatted that contains one
 or more component layers.
@@ -1475,7 +1498,7 @@
 be used.
  4. All component layers **must be** at the same Vulkan API major and minor
 version for the meta-layer to be used.
- 
+
 The ordering of a meta-layer's component layers in the instance or device
 call-chain is simple:
   * The first layer listed will be the layer closest to the application.
@@ -1584,7 +1607,7 @@
 ##### Associating Private Data with Vulkan Objects Within a Layer
 
 A layer may want to associate its own private data with one or more Vulkan
-objects.  Two common methods to do this are hash maps and object wrapping. 
+objects.  Two common methods to do this are hash maps and object wrapping.
 
 
 ###### Wrapping
@@ -1987,7 +2010,7 @@
   * [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 Vulkan Entry Point Discovery](#icd-vulkan-entry-point-discovery)
   * [ICD API Version](#icd-api-version)
   * [ICD Unknown Physical Device Extensions](#icd-unknown-physical-device-extensions)
   * [ICD Dispatchable Object Creation](#icd-dispatchable-object-creation)
@@ -2288,7 +2311,7 @@
  * "library\_path"
  * "api\_version"
 
- 
+
 ###  ICD Vulkan Entry Point Discovery
 
 The Vulkan symbols exported by an ICD must not clash with the loader's exported
@@ -2305,11 +2328,11 @@
 ```
 
 This function has very similar semantics to `vkGetInstanceProcAddr`.
-`vk_icdGetInstanceProcAddr` returns valid function pointers for all the 
+`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 
+`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.
@@ -2323,7 +2346,7 @@
 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
@@ -2352,7 +2375,7 @@
 will perform the following steps:
 
 1. Check the ICD's JSON manifest file for the "api_version" field.
-2. If the JSON version is greater greater than or equal to 1.1, Load the ICD's dynamic library
+2. If the JSON version is greater than or equal to 1.1, Load the ICD's dynamic library
 3. Call the ICD's `vkGetInstanceProcAddr` command to get a pointer to
 `vkEnumerateInstanceVersion`
 4. If the pointer to `vkEnumerateInstanceVersion` is not `NULL`, it will be
@@ -2449,6 +2472,35 @@
 attempting to use the commands.
 
 
+### Physical Device Sorting
+
+When an application selects a GPU to use, it must enumerate physical devices or physical device groups.
+These API functions do not specify which order the physical devices or physical device groups will be presented in.
+On Windows, the loader will attempt to sort these objects so that the system preference will be listed first.
+This mechanism does not force an application to use any particular GPU &mdash; it merely changes the order in which they are presented.
+
+This mechanism requires that an ICD implement version 6 of the loader/ICD interface.
+Version 6 of this interface defines a new method that the ICD may provide on Windows:
+
+```c
+VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+```
+
+This function takes an adapter LUID as input, and enumerates all Vulkan physical devices that are associated with that LUID.
+This works in the same way as other Vulkan enumerations &mdash; if `pPhysicalDevices` is `NULL`, then the count will be provided.
+Otherwise, the physical devices associated with the queried adapter will be provided.
+The function must provide multiple physical devices when the LUID referes to a linked adapter.
+This allows the loader to translate the adapter into Vulkan physical device groups.
+
+While the loader attempts to match the system's preference for GPU ordering, there are some limitations.
+Because this feature requires a new ICD interface, only physical devices from ICDs that support this function will be sorted.
+All unsorted physical devices will be listed at the end of the list, in an indeterminate order.
+Furthermore, only physical devices that correspond to an adapter may be sorted.
+This means that a software implementation would likely not be sorted.
+Finally, this API only applies to Windows systems and will only work on versions of Windows 10 that support GPU selection through the OS.
+Other platforms may be included in the future, but they will require separate platform-specific interfaces.
+
+
 ### ICD Dispatchable Object Creation
 
 As previously covered, the loader requires dispatch tables to be accessible
@@ -2464,7 +2516,7 @@
    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 
+     * 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
@@ -2489,7 +2541,7 @@
     return newObj;
 }
 ```
- 
+
 
 ### Handling KHR Surface Objects in WSI Extensions
 
@@ -2617,6 +2669,11 @@
 `vk_icdGetInstanceProcAddr` first, it supports at least version 1.  Otherwise,
 the loader only supports version 0.
 
+##### Loader Version 6 Interface Requirements
+
+Version 6 provides a mechanism to allow the loader to sort physical devices.
+The loader will only attempt to sort physical devices on an ICD if version 6 of the interface is supported.
+This version provides the `vk_icdEnumerateAdapterPhysicalDevices` function defined earlier in this document.
 
 ##### Loader Version 5 Interface Requirements
 
@@ -2741,7 +2798,7 @@
 | VK_LAYER_PATH                     | Override the loader's standard Layer library search folders and use the provided delimited folders to search for layer Manifest files. | `export VK_LAYER_PATH=<path_a>:<path_b>`<br/><br/>`set VK_LAYER_PATH=<path_a>;<path_b>` |
 | VK_LOADER_DISABLE_INST_EXT_FILTER | Disable the filtering out of instance extensions that the loader doesn't know about.  This will allow applications to enable instance extensions exposed by ICDs but that the loader has no support for.  **NOTE:** This may cause the loader or application to crash. |  `export VK_LOADER_DISABLE_INST_EXT_FILTER=1`<br/><br/>`set VK_LOADER_DISABLE_INST_EXT_FILTER=1` |
 | VK_LOADER_DEBUG                   | Enable loader debug messages.  Options are:<br/>- error (only errors)<br/>- warn (warnings and errors)<br/>- info (info, warning, and errors)<br/> - debug (debug + all before) <br/> -all (report out all messages) | `export VK_LOADER_DEBUG=all`<br/><br/>`set VK_LOADER_DEBUG=warn` |
- 
+
 ## Glossary of Terms
 
 | Field Name | Field Value |
diff --git a/loader/dxgi_loader.c b/loader/dxgi_loader.c
deleted file mode 100644
index c2a3fa5..0000000
--- a/loader/dxgi_loader.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "dxgi_loader.h"
-
-#include <strsafe.h>
-
-static HMODULE load_dxgi_module() {
-    TCHAR systemPath[MAX_PATH] = "";
-    GetSystemDirectory(systemPath, MAX_PATH);
-    StringCchCat(systemPath, MAX_PATH, TEXT("\\dxgi.dll"));
-
-    return LoadLibrary(systemPath);
-}
-
-typedef HRESULT (APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory);
-
-HRESULT dyn_CreateDXGIFactory1(REFIID riid, void **ppFactory) {
-    PFN_CreateDXGIFactory1 fpCreateDXGIFactory1 =
-        (PFN_CreateDXGIFactory1)GetProcAddress(load_dxgi_module(), "CreateDXGIFactory1");
-
-    if (fpCreateDXGIFactory1 != NULL)
-        return fpCreateDXGIFactory1(riid, ppFactory);
-
-    return DXGI_ERROR_NOT_FOUND;
-}
\ No newline at end of file
diff --git a/loader/dxgi_loader.h b/loader/dxgi_loader.h
deleted file mode 100644
index 00daf08..0000000
--- a/loader/dxgi_loader.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef DXGI_LOADER_H
-#define DXGI_LOADER_H
-
-#include <dxgi1_2.h>
-
-HRESULT dyn_CreateDXGIFactory1(REFIID riid, void **ppFactory);
-
-#endif
\ No newline at end of file
diff --git a/loader/generated/vk_dispatch_table_helper.h b/loader/generated/vk_dispatch_table_helper.h
index 6e3ee52..cc95bad 100644
--- a/loader/generated/vk_dispatch_table_helper.h
+++ b/loader/generated/vk_dispatch_table_helper.h
@@ -124,6 +124,7 @@
 static VKAPI_ATTR void VKAPI_CALL StubCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index) {  };
 static VKAPI_ATTR void VKAPI_CALL StubCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride) {  };
 static VKAPI_ATTR uint32_t VKAPI_CALL StubGetImageViewHandleNVX(VkDevice device, const VkImageViewHandleInfoNVX* pInfo) { return 0; };
+static VKAPI_ATTR VkResult VKAPI_CALL StubGetImageViewAddressNVX(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX* pProperties) { return VK_SUCCESS; };
 static VKAPI_ATTR void VKAPI_CALL StubCmdDrawIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {  };
 static VKAPI_ATTR void VKAPI_CALL StubCmdDrawIndexedIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {  };
 static VKAPI_ATTR VkResult VKAPI_CALL StubGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo) { return VK_SUCCESS; };
@@ -203,12 +204,28 @@
 #endif // VK_USE_PLATFORM_WIN32_KHR
 static VKAPI_ATTR void VKAPI_CALL StubCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern) {  };
 static VKAPI_ATTR void VKAPI_CALL StubResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetCullModeEXT(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetFrontFaceEXT(VkCommandBuffer commandBuffer, VkFrontFace frontFace) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetViewportWithCountEXT(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetScissorWithCountEXT(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdBindVertexBuffers2EXT(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetDepthTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetDepthWriteEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetDepthCompareOpEXT(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetStencilTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdSetStencilOpEXT(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp) {  };
 static VKAPI_ATTR void VKAPI_CALL StubGetGeneratedCommandsMemoryRequirementsNV(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements) {  };
 static VKAPI_ATTR void VKAPI_CALL StubCmdPreprocessGeneratedCommandsNV(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo) {  };
 static VKAPI_ATTR void VKAPI_CALL StubCmdExecuteGeneratedCommandsNV(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo) {  };
 static VKAPI_ATTR void VKAPI_CALL StubCmdBindPipelineShaderGroupNV(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex) {  };
 static VKAPI_ATTR VkResult VKAPI_CALL StubCreateIndirectCommandsLayoutNV(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNV* pIndirectCommandsLayout) { return VK_SUCCESS; };
 static VKAPI_ATTR void VKAPI_CALL StubDestroyIndirectCommandsLayoutNV(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks* pAllocator) {  };
+static VKAPI_ATTR VkResult VKAPI_CALL StubCreatePrivateDataSlotEXT(VkDevice device, const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlotEXT* pPrivateDataSlot) { return VK_SUCCESS; };
+static VKAPI_ATTR void VKAPI_CALL StubDestroyPrivateDataSlotEXT(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks* pAllocator) {  };
+static VKAPI_ATTR VkResult VKAPI_CALL StubSetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data) { return VK_SUCCESS; };
+static VKAPI_ATTR void VKAPI_CALL StubGetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t* pData) {  };
 #ifdef VK_USE_PLATFORM_FUCHSIA
 static VKAPI_ATTR VkResult VKAPI_CALL StubCreateBufferCollectionFUCHSIA(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA* pImportInfo, const VkAllocationCallbacks* pAllocator, VkBufferCollectionFUCHSIA* pCollection) { return VK_SUCCESS; };
 #endif // VK_USE_PLATFORM_FUCHSIA
@@ -246,7 +263,7 @@
 static VKAPI_ATTR void VKAPI_CALL StubCmdBuildAccelerationStructureKHR(VkCommandBuffer                                    commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos) {  };
 #endif // VK_ENABLE_BETA_EXTENSIONS
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-static VKAPI_ATTR void VKAPI_CALL StubCmdBuildAccelerationStructureIndirectKHR(VkCommandBuffer                                    commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR* pInfo, VkBuffer                                           indirectBuffer, VkDeviceSize                                       indirectOffset, uint32_t                                           indirectStride) {  };
+static VKAPI_ATTR void VKAPI_CALL StubCmdBuildAccelerationStructureIndirectKHR(VkCommandBuffer                  commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR* pInfo, VkBuffer                                           indirectBuffer, VkDeviceSize                                       indirectOffset, uint32_t                                           indirectStride) {  };
 #endif // VK_ENABLE_BETA_EXTENSIONS
 #ifdef VK_ENABLE_BETA_EXTENSIONS
 static VKAPI_ATTR VkResult VKAPI_CALL StubBuildAccelerationStructureKHR(VkDevice                                           device, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildOffsetInfoKHR* const* ppOffsetInfos) { return VK_SUCCESS; };
@@ -614,6 +631,8 @@
     if (table->CmdDrawIndirectByteCountEXT == nullptr) { table->CmdDrawIndirectByteCountEXT = (PFN_vkCmdDrawIndirectByteCountEXT)StubCmdDrawIndirectByteCountEXT; }
     table->GetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX) gpa(device, "vkGetImageViewHandleNVX");
     if (table->GetImageViewHandleNVX == nullptr) { table->GetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)StubGetImageViewHandleNVX; }
+    table->GetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX) gpa(device, "vkGetImageViewAddressNVX");
+    if (table->GetImageViewAddressNVX == nullptr) { table->GetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)StubGetImageViewAddressNVX; }
     table->CmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD) gpa(device, "vkCmdDrawIndirectCountAMD");
     if (table->CmdDrawIndirectCountAMD == nullptr) { table->CmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)StubCmdDrawIndirectCountAMD; }
     table->CmdDrawIndexedIndirectCountAMD = (PFN_vkCmdDrawIndexedIndirectCountAMD) gpa(device, "vkCmdDrawIndexedIndirectCountAMD");
@@ -768,6 +787,30 @@
     if (table->CmdSetLineStippleEXT == nullptr) { table->CmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT)StubCmdSetLineStippleEXT; }
     table->ResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT) gpa(device, "vkResetQueryPoolEXT");
     if (table->ResetQueryPoolEXT == nullptr) { table->ResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)StubResetQueryPoolEXT; }
+    table->CmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT) gpa(device, "vkCmdSetCullModeEXT");
+    if (table->CmdSetCullModeEXT == nullptr) { table->CmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)StubCmdSetCullModeEXT; }
+    table->CmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT) gpa(device, "vkCmdSetFrontFaceEXT");
+    if (table->CmdSetFrontFaceEXT == nullptr) { table->CmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)StubCmdSetFrontFaceEXT; }
+    table->CmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT) gpa(device, "vkCmdSetPrimitiveTopologyEXT");
+    if (table->CmdSetPrimitiveTopologyEXT == nullptr) { table->CmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)StubCmdSetPrimitiveTopologyEXT; }
+    table->CmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT) gpa(device, "vkCmdSetViewportWithCountEXT");
+    if (table->CmdSetViewportWithCountEXT == nullptr) { table->CmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)StubCmdSetViewportWithCountEXT; }
+    table->CmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT) gpa(device, "vkCmdSetScissorWithCountEXT");
+    if (table->CmdSetScissorWithCountEXT == nullptr) { table->CmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)StubCmdSetScissorWithCountEXT; }
+    table->CmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT) gpa(device, "vkCmdBindVertexBuffers2EXT");
+    if (table->CmdBindVertexBuffers2EXT == nullptr) { table->CmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)StubCmdBindVertexBuffers2EXT; }
+    table->CmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT) gpa(device, "vkCmdSetDepthTestEnableEXT");
+    if (table->CmdSetDepthTestEnableEXT == nullptr) { table->CmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)StubCmdSetDepthTestEnableEXT; }
+    table->CmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT) gpa(device, "vkCmdSetDepthWriteEnableEXT");
+    if (table->CmdSetDepthWriteEnableEXT == nullptr) { table->CmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)StubCmdSetDepthWriteEnableEXT; }
+    table->CmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT) gpa(device, "vkCmdSetDepthCompareOpEXT");
+    if (table->CmdSetDepthCompareOpEXT == nullptr) { table->CmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)StubCmdSetDepthCompareOpEXT; }
+    table->CmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT) gpa(device, "vkCmdSetDepthBoundsTestEnableEXT");
+    if (table->CmdSetDepthBoundsTestEnableEXT == nullptr) { table->CmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)StubCmdSetDepthBoundsTestEnableEXT; }
+    table->CmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT) gpa(device, "vkCmdSetStencilTestEnableEXT");
+    if (table->CmdSetStencilTestEnableEXT == nullptr) { table->CmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)StubCmdSetStencilTestEnableEXT; }
+    table->CmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT) gpa(device, "vkCmdSetStencilOpEXT");
+    if (table->CmdSetStencilOpEXT == nullptr) { table->CmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)StubCmdSetStencilOpEXT; }
     table->GetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV) gpa(device, "vkGetGeneratedCommandsMemoryRequirementsNV");
     if (table->GetGeneratedCommandsMemoryRequirementsNV == nullptr) { table->GetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)StubGetGeneratedCommandsMemoryRequirementsNV; }
     table->CmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV) gpa(device, "vkCmdPreprocessGeneratedCommandsNV");
@@ -780,6 +823,14 @@
     if (table->CreateIndirectCommandsLayoutNV == nullptr) { table->CreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)StubCreateIndirectCommandsLayoutNV; }
     table->DestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV) gpa(device, "vkDestroyIndirectCommandsLayoutNV");
     if (table->DestroyIndirectCommandsLayoutNV == nullptr) { table->DestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)StubDestroyIndirectCommandsLayoutNV; }
+    table->CreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT) gpa(device, "vkCreatePrivateDataSlotEXT");
+    if (table->CreatePrivateDataSlotEXT == nullptr) { table->CreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)StubCreatePrivateDataSlotEXT; }
+    table->DestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT) gpa(device, "vkDestroyPrivateDataSlotEXT");
+    if (table->DestroyPrivateDataSlotEXT == nullptr) { table->DestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)StubDestroyPrivateDataSlotEXT; }
+    table->SetPrivateDataEXT = (PFN_vkSetPrivateDataEXT) gpa(device, "vkSetPrivateDataEXT");
+    if (table->SetPrivateDataEXT == nullptr) { table->SetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)StubSetPrivateDataEXT; }
+    table->GetPrivateDataEXT = (PFN_vkGetPrivateDataEXT) gpa(device, "vkGetPrivateDataEXT");
+    if (table->GetPrivateDataEXT == nullptr) { table->GetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)StubGetPrivateDataEXT; }
 #ifdef VK_USE_PLATFORM_FUCHSIA
     table->CreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA) gpa(device, "vkCreateBufferCollectionFUCHSIA");
     if (table->CreateBufferCollectionFUCHSIA == nullptr) { table->CreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)StubCreateBufferCollectionFUCHSIA; }
@@ -1018,4 +1069,10 @@
     table->GetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT) gpa(instance, "vkGetPhysicalDeviceSurfacePresentModes2EXT");
 #endif // VK_USE_PLATFORM_WIN32_KHR
     table->CreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT) gpa(instance, "vkCreateHeadlessSurfaceEXT");
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    table->CreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT) gpa(instance, "vkCreateDirectFBSurfaceEXT");
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    table->GetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT) gpa(instance, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT");
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
 }
diff --git a/loader/generated/vk_layer_dispatch_table.h b/loader/generated/vk_layer_dispatch_table.h
index b148e15..f4cde02 100644
--- a/loader/generated/vk_layer_dispatch_table.h
+++ b/loader/generated/vk_layer_dispatch_table.h
@@ -233,6 +233,14 @@
 
     // ---- VK_EXT_headless_surface extension commands
     PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT;
+
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    PFN_vkCreateDirectFBSurfaceEXT CreateDirectFBSurfaceEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT GetPhysicalDeviceDirectFBPresentationSupportEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
 } VkLayerInstanceDispatchTable;
 
 // Device function pointer dispatch table
@@ -542,6 +550,7 @@
 
     // ---- VK_NVX_image_view_handle extension commands
     PFN_vkGetImageViewHandleNVX GetImageViewHandleNVX;
+    PFN_vkGetImageViewAddressNVX GetImageViewAddressNVX;
 
     // ---- VK_AMD_draw_indirect_count extension commands
     PFN_vkCmdDrawIndirectCountAMD CmdDrawIndirectCountAMD;
@@ -686,6 +695,20 @@
     // ---- VK_EXT_host_query_reset extension commands
     PFN_vkResetQueryPoolEXT ResetQueryPoolEXT;
 
+    // ---- VK_EXT_extended_dynamic_state extension commands
+    PFN_vkCmdSetCullModeEXT CmdSetCullModeEXT;
+    PFN_vkCmdSetFrontFaceEXT CmdSetFrontFaceEXT;
+    PFN_vkCmdSetPrimitiveTopologyEXT CmdSetPrimitiveTopologyEXT;
+    PFN_vkCmdSetViewportWithCountEXT CmdSetViewportWithCountEXT;
+    PFN_vkCmdSetScissorWithCountEXT CmdSetScissorWithCountEXT;
+    PFN_vkCmdBindVertexBuffers2EXT CmdBindVertexBuffers2EXT;
+    PFN_vkCmdSetDepthTestEnableEXT CmdSetDepthTestEnableEXT;
+    PFN_vkCmdSetDepthWriteEnableEXT CmdSetDepthWriteEnableEXT;
+    PFN_vkCmdSetDepthCompareOpEXT CmdSetDepthCompareOpEXT;
+    PFN_vkCmdSetDepthBoundsTestEnableEXT CmdSetDepthBoundsTestEnableEXT;
+    PFN_vkCmdSetStencilTestEnableEXT CmdSetStencilTestEnableEXT;
+    PFN_vkCmdSetStencilOpEXT CmdSetStencilOpEXT;
+
     // ---- VK_NV_device_generated_commands extension commands
     PFN_vkGetGeneratedCommandsMemoryRequirementsNV GetGeneratedCommandsMemoryRequirementsNV;
     PFN_vkCmdPreprocessGeneratedCommandsNV CmdPreprocessGeneratedCommandsNV;
@@ -694,6 +717,12 @@
     PFN_vkCreateIndirectCommandsLayoutNV CreateIndirectCommandsLayoutNV;
     PFN_vkDestroyIndirectCommandsLayoutNV DestroyIndirectCommandsLayoutNV;
 
+    // ---- VK_EXT_private_data extension commands
+    PFN_vkCreatePrivateDataSlotEXT CreatePrivateDataSlotEXT;
+    PFN_vkDestroyPrivateDataSlotEXT DestroyPrivateDataSlotEXT;
+    PFN_vkSetPrivateDataEXT SetPrivateDataEXT;
+    PFN_vkGetPrivateDataEXT GetPrivateDataEXT;
+
     // ---- VK_FUCHSIA_buffer_collection extension commands
 #ifdef VK_USE_PLATFORM_FUCHSIA
     PFN_vkCreateBufferCollectionFUCHSIA CreateBufferCollectionFUCHSIA;
diff --git a/loader/generated/vk_loader_extensions.c b/loader/generated/vk_loader_extensions.c
index b53fb3a..3632c44 100644
--- a/loader/generated/vk_loader_extensions.c
+++ b/loader/generated/vk_loader_extensions.c
@@ -281,6 +281,14 @@
     // ---- VK_EXT_headless_surface extension commands
     LOOKUP_GIPA(CreateHeadlessSurfaceEXT, false);
 
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    LOOKUP_GIPA(CreateDirectFBSurfaceEXT, false);
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    LOOKUP_GIPA(GetPhysicalDeviceDirectFBPresentationSupportEXT, false);
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+
 #undef LOOKUP_GIPA
 
     return true;
@@ -605,6 +613,7 @@
 
     // ---- VK_NVX_image_view_handle extension commands
     table->GetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX)gdpa(dev, "vkGetImageViewHandleNVX");
+    table->GetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX)gdpa(dev, "vkGetImageViewAddressNVX");
 
     // ---- VK_AMD_draw_indirect_count extension commands
     table->CmdDrawIndirectCountAMD = (PFN_vkCmdDrawIndirectCountAMD)gdpa(dev, "vkCmdDrawIndirectCountAMD");
@@ -749,6 +758,20 @@
     // ---- VK_EXT_host_query_reset extension commands
     table->ResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT)gdpa(dev, "vkResetQueryPoolEXT");
 
+    // ---- VK_EXT_extended_dynamic_state extension commands
+    table->CmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)gdpa(dev, "vkCmdSetCullModeEXT");
+    table->CmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)gdpa(dev, "vkCmdSetFrontFaceEXT");
+    table->CmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)gdpa(dev, "vkCmdSetPrimitiveTopologyEXT");
+    table->CmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)gdpa(dev, "vkCmdSetViewportWithCountEXT");
+    table->CmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)gdpa(dev, "vkCmdSetScissorWithCountEXT");
+    table->CmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT)gdpa(dev, "vkCmdBindVertexBuffers2EXT");
+    table->CmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)gdpa(dev, "vkCmdSetDepthTestEnableEXT");
+    table->CmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)gdpa(dev, "vkCmdSetDepthWriteEnableEXT");
+    table->CmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)gdpa(dev, "vkCmdSetDepthCompareOpEXT");
+    table->CmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)gdpa(dev, "vkCmdSetDepthBoundsTestEnableEXT");
+    table->CmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)gdpa(dev, "vkCmdSetStencilTestEnableEXT");
+    table->CmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)gdpa(dev, "vkCmdSetStencilOpEXT");
+
     // ---- VK_NV_device_generated_commands extension commands
     table->GetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV)gdpa(dev, "vkGetGeneratedCommandsMemoryRequirementsNV");
     table->CmdPreprocessGeneratedCommandsNV = (PFN_vkCmdPreprocessGeneratedCommandsNV)gdpa(dev, "vkCmdPreprocessGeneratedCommandsNV");
@@ -757,6 +780,12 @@
     table->CreateIndirectCommandsLayoutNV = (PFN_vkCreateIndirectCommandsLayoutNV)gdpa(dev, "vkCreateIndirectCommandsLayoutNV");
     table->DestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV)gdpa(dev, "vkDestroyIndirectCommandsLayoutNV");
 
+    // ---- VK_EXT_private_data extension commands
+    table->CreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT)gdpa(dev, "vkCreatePrivateDataSlotEXT");
+    table->DestroyPrivateDataSlotEXT = (PFN_vkDestroyPrivateDataSlotEXT)gdpa(dev, "vkDestroyPrivateDataSlotEXT");
+    table->SetPrivateDataEXT = (PFN_vkSetPrivateDataEXT)gdpa(dev, "vkSetPrivateDataEXT");
+    table->GetPrivateDataEXT = (PFN_vkGetPrivateDataEXT)gdpa(dev, "vkGetPrivateDataEXT");
+
     // ---- VK_FUCHSIA_buffer_collection extension commands
 #ifdef VK_USE_PLATFORM_FUCHSIA
     table->CreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA)gdpa(dev, "vkCreateBufferCollectionFUCHSIA");
@@ -1053,6 +1082,14 @@
 
     // ---- VK_EXT_headless_surface extension commands
     table->CreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)gpa(inst, "vkCreateHeadlessSurfaceEXT");
+
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    table->CreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT)gpa(inst, "vkCreateDirectFBSurfaceEXT");
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    table->GetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)gpa(inst, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT");
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
 }
 
 // Device command lookup function
@@ -1365,6 +1402,7 @@
 
     // ---- VK_NVX_image_view_handle extension commands
     if (!strcmp(name, "GetImageViewHandleNVX")) return (void *)table->GetImageViewHandleNVX;
+    if (!strcmp(name, "GetImageViewAddressNVX")) return (void *)table->GetImageViewAddressNVX;
 
     // ---- VK_AMD_draw_indirect_count extension commands
     if (!strcmp(name, "CmdDrawIndirectCountAMD")) return (void *)table->CmdDrawIndirectCountAMD;
@@ -1509,6 +1547,20 @@
     // ---- VK_EXT_host_query_reset extension commands
     if (!strcmp(name, "ResetQueryPoolEXT")) return (void *)table->ResetQueryPoolEXT;
 
+    // ---- VK_EXT_extended_dynamic_state extension commands
+    if (!strcmp(name, "CmdSetCullModeEXT")) return (void *)table->CmdSetCullModeEXT;
+    if (!strcmp(name, "CmdSetFrontFaceEXT")) return (void *)table->CmdSetFrontFaceEXT;
+    if (!strcmp(name, "CmdSetPrimitiveTopologyEXT")) return (void *)table->CmdSetPrimitiveTopologyEXT;
+    if (!strcmp(name, "CmdSetViewportWithCountEXT")) return (void *)table->CmdSetViewportWithCountEXT;
+    if (!strcmp(name, "CmdSetScissorWithCountEXT")) return (void *)table->CmdSetScissorWithCountEXT;
+    if (!strcmp(name, "CmdBindVertexBuffers2EXT")) return (void *)table->CmdBindVertexBuffers2EXT;
+    if (!strcmp(name, "CmdSetDepthTestEnableEXT")) return (void *)table->CmdSetDepthTestEnableEXT;
+    if (!strcmp(name, "CmdSetDepthWriteEnableEXT")) return (void *)table->CmdSetDepthWriteEnableEXT;
+    if (!strcmp(name, "CmdSetDepthCompareOpEXT")) return (void *)table->CmdSetDepthCompareOpEXT;
+    if (!strcmp(name, "CmdSetDepthBoundsTestEnableEXT")) return (void *)table->CmdSetDepthBoundsTestEnableEXT;
+    if (!strcmp(name, "CmdSetStencilTestEnableEXT")) return (void *)table->CmdSetStencilTestEnableEXT;
+    if (!strcmp(name, "CmdSetStencilOpEXT")) return (void *)table->CmdSetStencilOpEXT;
+
     // ---- VK_NV_device_generated_commands extension commands
     if (!strcmp(name, "GetGeneratedCommandsMemoryRequirementsNV")) return (void *)table->GetGeneratedCommandsMemoryRequirementsNV;
     if (!strcmp(name, "CmdPreprocessGeneratedCommandsNV")) return (void *)table->CmdPreprocessGeneratedCommandsNV;
@@ -1517,6 +1569,12 @@
     if (!strcmp(name, "CreateIndirectCommandsLayoutNV")) return (void *)table->CreateIndirectCommandsLayoutNV;
     if (!strcmp(name, "DestroyIndirectCommandsLayoutNV")) return (void *)table->DestroyIndirectCommandsLayoutNV;
 
+    // ---- VK_EXT_private_data extension commands
+    if (!strcmp(name, "CreatePrivateDataSlotEXT")) return (void *)table->CreatePrivateDataSlotEXT;
+    if (!strcmp(name, "DestroyPrivateDataSlotEXT")) return (void *)table->DestroyPrivateDataSlotEXT;
+    if (!strcmp(name, "SetPrivateDataEXT")) return (void *)table->SetPrivateDataEXT;
+    if (!strcmp(name, "GetPrivateDataEXT")) return (void *)table->GetPrivateDataEXT;
+
     // ---- VK_FUCHSIA_buffer_collection extension commands
 #ifdef VK_USE_PLATFORM_FUCHSIA
     if (!strcmp(name, "CreateBufferCollectionFUCHSIA")) return (void *)table->CreateBufferCollectionFUCHSIA;
@@ -1818,6 +1876,14 @@
     // ---- VK_EXT_headless_surface extension commands
     if (!strcmp(name, "CreateHeadlessSurfaceEXT")) return (void *)table->CreateHeadlessSurfaceEXT;
 
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    if (!strcmp(name, "CreateDirectFBSurfaceEXT")) return (void *)table->CreateDirectFBSurfaceEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    if (!strcmp(name, "GetPhysicalDeviceDirectFBPresentationSupportEXT")) return (void *)table->GetPhysicalDeviceDirectFBPresentationSupportEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+
     *found_name = false;
     return NULL;
 }
@@ -2570,6 +2636,14 @@
     return disp->GetImageViewHandleNVX(device, pInfo);
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL GetImageViewAddressNVX(
+    VkDevice                                    device,
+    VkImageView                                 imageView,
+    VkImageViewAddressPropertiesNVX*            pProperties) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    return disp->GetImageViewAddressNVX(device, imageView, pProperties);
+}
+
 
 // ---- VK_AMD_draw_indirect_count extension trampoline/terminators
 
@@ -3601,6 +3675,104 @@
 }
 
 
+// ---- VK_EXT_extended_dynamic_state extension trampoline/terminators
+
+VKAPI_ATTR void VKAPI_CALL CmdSetCullModeEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkCullModeFlags                             cullMode) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetCullModeEXT(commandBuffer, cullMode);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetFrontFaceEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkFrontFace                                 frontFace) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetFrontFaceEXT(commandBuffer, frontFace);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetPrimitiveTopologyEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkPrimitiveTopology                         primitiveTopology) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetPrimitiveTopologyEXT(commandBuffer, primitiveTopology);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetViewportWithCountEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    viewportCount,
+    const VkViewport*                           pViewports) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetViewportWithCountEXT(commandBuffer, viewportCount, pViewports);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetScissorWithCountEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    scissorCount,
+    const VkRect2D*                             pScissors) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetScissorWithCountEXT(commandBuffer, scissorCount, pScissors);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers2EXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstBinding,
+    uint32_t                                    bindingCount,
+    const VkBuffer*                             pBuffers,
+    const VkDeviceSize*                         pOffsets,
+    const VkDeviceSize*                         pSizes,
+    const VkDeviceSize*                         pStrides) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdBindVertexBuffers2EXT(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets, pSizes, pStrides);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetDepthTestEnableEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBool32                                    depthTestEnable) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetDepthTestEnableEXT(commandBuffer, depthTestEnable);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetDepthWriteEnableEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBool32                                    depthWriteEnable) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetDepthWriteEnableEXT(commandBuffer, depthWriteEnable);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetDepthCompareOpEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkCompareOp                                 depthCompareOp) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetDepthCompareOpEXT(commandBuffer, depthCompareOp);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetDepthBoundsTestEnableEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBool32                                    depthBoundsTestEnable) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetDepthBoundsTestEnableEXT(commandBuffer, depthBoundsTestEnable);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetStencilTestEnableEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBool32                                    stencilTestEnable) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetStencilTestEnableEXT(commandBuffer, stencilTestEnable);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetStencilOpEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkStencilFaceFlags                          faceMask,
+    VkStencilOp                                 failOp,
+    VkStencilOp                                 passOp,
+    VkStencilOp                                 depthFailOp,
+    VkCompareOp                                 compareOp) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
+    disp->CmdSetStencilOpEXT(commandBuffer, faceMask, failOp, passOp, depthFailOp, compareOp);
+}
+
+
 // ---- VK_NV_device_generated_commands extension trampoline/terminators
 
 VKAPI_ATTR void VKAPI_CALL GetGeneratedCommandsMemoryRequirementsNV(
@@ -3653,6 +3825,46 @@
 }
 
 
+// ---- VK_EXT_private_data extension trampoline/terminators
+
+VKAPI_ATTR VkResult VKAPI_CALL CreatePrivateDataSlotEXT(
+    VkDevice                                    device,
+    const VkPrivateDataSlotCreateInfoEXT*       pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPrivateDataSlotEXT*                       pPrivateDataSlot) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    return disp->CreatePrivateDataSlotEXT(device, pCreateInfo, pAllocator, pPrivateDataSlot);
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyPrivateDataSlotEXT(
+    VkDevice                                    device,
+    VkPrivateDataSlotEXT                        privateDataSlot,
+    const VkAllocationCallbacks*                pAllocator) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    disp->DestroyPrivateDataSlotEXT(device, privateDataSlot, pAllocator);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL SetPrivateDataEXT(
+    VkDevice                                    device,
+    VkObjectType                                objectType,
+    uint64_t                                    objectHandle,
+    VkPrivateDataSlotEXT                        privateDataSlot,
+    uint64_t                                    data) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    return disp->SetPrivateDataEXT(device, objectType, objectHandle, privateDataSlot, data);
+}
+
+VKAPI_ATTR void VKAPI_CALL GetPrivateDataEXT(
+    VkDevice                                    device,
+    VkObjectType                                objectType,
+    uint64_t                                    objectHandle,
+    VkPrivateDataSlotEXT                        privateDataSlot,
+    uint64_t*                                   pData) {
+    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
+    disp->GetPrivateDataEXT(device, objectType, objectHandle, privateDataSlot, pData);
+}
+
+
 // ---- VK_FUCHSIA_buffer_collection extension trampoline/terminators
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
@@ -4367,6 +4579,10 @@
         *addr = (void *)GetImageViewHandleNVX;
         return true;
     }
+    if (!strcmp("vkGetImageViewAddressNVX", name)) {
+        *addr = (void *)GetImageViewAddressNVX;
+        return true;
+    }
 
     // ---- VK_AMD_draw_indirect_count extension commands
     if (!strcmp("vkCmdDrawIndirectCountAMD", name)) {
@@ -4846,6 +5062,56 @@
         return true;
     }
 
+    // ---- VK_EXT_extended_dynamic_state extension commands
+    if (!strcmp("vkCmdSetCullModeEXT", name)) {
+        *addr = (void *)CmdSetCullModeEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetFrontFaceEXT", name)) {
+        *addr = (void *)CmdSetFrontFaceEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetPrimitiveTopologyEXT", name)) {
+        *addr = (void *)CmdSetPrimitiveTopologyEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetViewportWithCountEXT", name)) {
+        *addr = (void *)CmdSetViewportWithCountEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetScissorWithCountEXT", name)) {
+        *addr = (void *)CmdSetScissorWithCountEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdBindVertexBuffers2EXT", name)) {
+        *addr = (void *)CmdBindVertexBuffers2EXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetDepthTestEnableEXT", name)) {
+        *addr = (void *)CmdSetDepthTestEnableEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetDepthWriteEnableEXT", name)) {
+        *addr = (void *)CmdSetDepthWriteEnableEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetDepthCompareOpEXT", name)) {
+        *addr = (void *)CmdSetDepthCompareOpEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetDepthBoundsTestEnableEXT", name)) {
+        *addr = (void *)CmdSetDepthBoundsTestEnableEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetStencilTestEnableEXT", name)) {
+        *addr = (void *)CmdSetStencilTestEnableEXT;
+        return true;
+    }
+    if (!strcmp("vkCmdSetStencilOpEXT", name)) {
+        *addr = (void *)CmdSetStencilOpEXT;
+        return true;
+    }
+
     // ---- VK_NV_device_generated_commands extension commands
     if (!strcmp("vkGetGeneratedCommandsMemoryRequirementsNV", name)) {
         *addr = (void *)GetGeneratedCommandsMemoryRequirementsNV;
@@ -4872,6 +5138,24 @@
         return true;
     }
 
+    // ---- VK_EXT_private_data extension commands
+    if (!strcmp("vkCreatePrivateDataSlotEXT", name)) {
+        *addr = (void *)CreatePrivateDataSlotEXT;
+        return true;
+    }
+    if (!strcmp("vkDestroyPrivateDataSlotEXT", name)) {
+        *addr = (void *)DestroyPrivateDataSlotEXT;
+        return true;
+    }
+    if (!strcmp("vkSetPrivateDataEXT", name)) {
+        *addr = (void *)SetPrivateDataEXT;
+        return true;
+    }
+    if (!strcmp("vkGetPrivateDataEXT", name)) {
+        *addr = (void *)GetPrivateDataEXT;
+        return true;
+    }
+
     // ---- VK_FUCHSIA_buffer_collection extension commands
 #ifdef VK_USE_PLATFORM_FUCHSIA
     if (!strcmp("vkCreateBufferCollectionFUCHSIA", name)) {
@@ -5370,6 +5654,14 @@
 
     // ---- VK_EXT_headless_surface extension commands
     .CreateHeadlessSurfaceEXT = terminator_CreateHeadlessSurfaceEXT,
+
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    .CreateDirectFBSurfaceEXT = terminator_CreateDirectFBSurfaceEXT,
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    .GetPhysicalDeviceDirectFBPresentationSupportEXT = terminator_GetPhysicalDeviceDirectFBPresentationSupportEXT,
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
 };
 
 // A null-terminated list of all of the instance extensions supported by the loader.
@@ -5429,5 +5721,8 @@
 #endif // VK_USE_PLATFORM_METAL_EXT
                                                   VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME,
                                                   VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME,
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+                                                  VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME,
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
                                                   NULL };
 
diff --git a/loader/generated/vk_loader_extensions.h b/loader/generated/vk_loader_extensions.h
index c46cc6d..b008dee 100644
--- a/loader/generated/vk_loader_extensions.h
+++ b/loader/generated/vk_loader_extensions.h
@@ -428,6 +428,14 @@
 
     // ---- VK_EXT_headless_surface extension commands
     PFN_vkCreateHeadlessSurfaceEXT CreateHeadlessSurfaceEXT;
+
+    // ---- VK_EXT_directfb_surface extension commands
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    PFN_vkCreateDirectFBSurfaceEXT CreateDirectFBSurfaceEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT GetPhysicalDeviceDirectFBPresentationSupportEXT;
+#endif // VK_USE_PLATFORM_DIRECTFB_EXT
 };
 
 union loader_instance_extension_enables {
diff --git a/loader/generated/vk_object_types.h b/loader/generated/vk_object_types.h
index 57fcdd1..5cef47c 100644
--- a/loader/generated/vk_object_types.h
+++ b/loader/generated/vk_object_types.h
@@ -37,16 +37,16 @@
 // Object Type enum for validation layer internal object handling
 typedef enum VulkanObjectType {
     kVulkanObjectTypeUnknown = 0,
-    kVulkanObjectTypeInstance = 1,
-    kVulkanObjectTypePhysicalDevice = 2,
-    kVulkanObjectTypeDevice = 3,
-    kVulkanObjectTypeQueue = 4,
-    kVulkanObjectTypeSemaphore = 5,
-    kVulkanObjectTypeCommandBuffer = 6,
-    kVulkanObjectTypeFence = 7,
-    kVulkanObjectTypeDeviceMemory = 8,
-    kVulkanObjectTypeBuffer = 9,
-    kVulkanObjectTypeImage = 10,
+    kVulkanObjectTypeBuffer = 1,
+    kVulkanObjectTypeImage = 2,
+    kVulkanObjectTypeInstance = 3,
+    kVulkanObjectTypePhysicalDevice = 4,
+    kVulkanObjectTypeDevice = 5,
+    kVulkanObjectTypeQueue = 6,
+    kVulkanObjectTypeSemaphore = 7,
+    kVulkanObjectTypeCommandBuffer = 8,
+    kVulkanObjectTypeFence = 9,
+    kVulkanObjectTypeDeviceMemory = 10,
     kVulkanObjectTypeEvent = 11,
     kVulkanObjectTypeQueryPool = 12,
     kVulkanObjectTypeBufferView = 13,
@@ -54,12 +54,12 @@
     kVulkanObjectTypeShaderModule = 15,
     kVulkanObjectTypePipelineCache = 16,
     kVulkanObjectTypePipelineLayout = 17,
-    kVulkanObjectTypeRenderPass = 18,
-    kVulkanObjectTypePipeline = 19,
+    kVulkanObjectTypePipeline = 18,
+    kVulkanObjectTypeRenderPass = 19,
     kVulkanObjectTypeDescriptorSetLayout = 20,
     kVulkanObjectTypeSampler = 21,
-    kVulkanObjectTypeDescriptorPool = 22,
-    kVulkanObjectTypeDescriptorSet = 23,
+    kVulkanObjectTypeDescriptorSet = 22,
+    kVulkanObjectTypeDescriptorPool = 23,
     kVulkanObjectTypeFramebuffer = 24,
     kVulkanObjectTypeCommandPool = 25,
     kVulkanObjectTypeSamplerYcbcrConversion = 26,
@@ -75,8 +75,9 @@
     kVulkanObjectTypeAccelerationStructureKHR = 36,
     kVulkanObjectTypePerformanceConfigurationINTEL = 37,
     kVulkanObjectTypeIndirectCommandsLayoutNV = 38,
-    kVulkanObjectTypeBufferCollectionFUCHSIA = 39,
-    kVulkanObjectTypeMax = 40,
+    kVulkanObjectTypePrivateDataSlotEXT = 39,
+    kVulkanObjectTypeBufferCollectionFUCHSIA = 40,
+    kVulkanObjectTypeMax = 41,
     // Aliases for backwards compatibilty of "promoted" types
     kVulkanObjectTypeDescriptorUpdateTemplateKHR = kVulkanObjectTypeDescriptorUpdateTemplate,
     kVulkanObjectTypeSamplerYcbcrConversionKHR = kVulkanObjectTypeSamplerYcbcrConversion,
@@ -86,6 +87,8 @@
 // Array of object name strings for OBJECT_TYPE enum conversion
 static const char * const object_string[kVulkanObjectTypeMax] = {
     "Unknown",
+    "Buffer",
+    "Image",
     "Instance",
     "PhysicalDevice",
     "Device",
@@ -94,8 +97,6 @@
     "CommandBuffer",
     "Fence",
     "DeviceMemory",
-    "Buffer",
-    "Image",
     "Event",
     "QueryPool",
     "BufferView",
@@ -103,12 +104,12 @@
     "ShaderModule",
     "PipelineCache",
     "PipelineLayout",
-    "RenderPass",
     "Pipeline",
+    "RenderPass",
     "DescriptorSetLayout",
     "Sampler",
-    "DescriptorPool",
     "DescriptorSet",
+    "DescriptorPool",
     "Framebuffer",
     "CommandPool",
     "SamplerYcbcrConversion",
@@ -124,12 +125,15 @@
     "AccelerationStructureKHR",
     "PerformanceConfigurationINTEL",
     "IndirectCommandsLayoutNV",
+    "PrivateDataSlotEXT",
     "BufferCollectionFUCHSIA",
 };
 
 // Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version
 const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {
     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown
+    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,   // kVulkanObjectTypeBuffer
+    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,   // kVulkanObjectTypeImage
     VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,   // kVulkanObjectTypeInstance
     VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,   // kVulkanObjectTypePhysicalDevice
     VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,   // kVulkanObjectTypeDevice
@@ -138,8 +142,6 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,   // kVulkanObjectTypeCommandBuffer
     VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,   // kVulkanObjectTypeFence
     VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,   // kVulkanObjectTypeDeviceMemory
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,   // kVulkanObjectTypeBuffer
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,   // kVulkanObjectTypeImage
     VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,   // kVulkanObjectTypeEvent
     VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT,   // kVulkanObjectTypeQueryPool
     VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT,   // kVulkanObjectTypeBufferView
@@ -147,12 +149,12 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,   // kVulkanObjectTypeShaderModule
     VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT,   // kVulkanObjectTypePipelineCache
     VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,   // kVulkanObjectTypePipelineLayout
-    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,   // kVulkanObjectTypeRenderPass
     VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,   // kVulkanObjectTypePipeline
+    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,   // kVulkanObjectTypeRenderPass
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,   // kVulkanObjectTypeDescriptorSetLayout
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,   // kVulkanObjectTypeSampler
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,   // kVulkanObjectTypeDescriptorPool
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,   // kVulkanObjectTypeDescriptorSet
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,   // kVulkanObjectTypeDescriptorPool
     VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,   // kVulkanObjectTypeFramebuffer
     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT,   // kVulkanObjectTypeCommandPool
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT,   // kVulkanObjectTypeSamplerYcbcrConversion
@@ -168,12 +170,15 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT,   // kVulkanObjectTypeAccelerationStructureKHR
     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,   // kVulkanObjectTypePerformanceConfigurationINTEL
     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,   // kVulkanObjectTypeIndirectCommandsLayoutNV
+    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,   // kVulkanObjectTypePrivateDataSlotEXT
     VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT,   // kVulkanObjectTypeBufferCollectionFUCHSIA
 };
 
 // Helper array to get Official Vulkan VkObjectType enum from the internal layers version
 const VkObjectType get_object_type_enum[] = {
     VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown
+    VK_OBJECT_TYPE_BUFFER,   // kVulkanObjectTypeBuffer
+    VK_OBJECT_TYPE_IMAGE,   // kVulkanObjectTypeImage
     VK_OBJECT_TYPE_INSTANCE,   // kVulkanObjectTypeInstance
     VK_OBJECT_TYPE_PHYSICAL_DEVICE,   // kVulkanObjectTypePhysicalDevice
     VK_OBJECT_TYPE_DEVICE,   // kVulkanObjectTypeDevice
@@ -182,8 +187,6 @@
     VK_OBJECT_TYPE_COMMAND_BUFFER,   // kVulkanObjectTypeCommandBuffer
     VK_OBJECT_TYPE_FENCE,   // kVulkanObjectTypeFence
     VK_OBJECT_TYPE_DEVICE_MEMORY,   // kVulkanObjectTypeDeviceMemory
-    VK_OBJECT_TYPE_BUFFER,   // kVulkanObjectTypeBuffer
-    VK_OBJECT_TYPE_IMAGE,   // kVulkanObjectTypeImage
     VK_OBJECT_TYPE_EVENT,   // kVulkanObjectTypeEvent
     VK_OBJECT_TYPE_QUERY_POOL,   // kVulkanObjectTypeQueryPool
     VK_OBJECT_TYPE_BUFFER_VIEW,   // kVulkanObjectTypeBufferView
@@ -191,12 +194,12 @@
     VK_OBJECT_TYPE_SHADER_MODULE,   // kVulkanObjectTypeShaderModule
     VK_OBJECT_TYPE_PIPELINE_CACHE,   // kVulkanObjectTypePipelineCache
     VK_OBJECT_TYPE_PIPELINE_LAYOUT,   // kVulkanObjectTypePipelineLayout
-    VK_OBJECT_TYPE_RENDER_PASS,   // kVulkanObjectTypeRenderPass
     VK_OBJECT_TYPE_PIPELINE,   // kVulkanObjectTypePipeline
+    VK_OBJECT_TYPE_RENDER_PASS,   // kVulkanObjectTypeRenderPass
     VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT,   // kVulkanObjectTypeDescriptorSetLayout
     VK_OBJECT_TYPE_SAMPLER,   // kVulkanObjectTypeSampler
-    VK_OBJECT_TYPE_DESCRIPTOR_POOL,   // kVulkanObjectTypeDescriptorPool
     VK_OBJECT_TYPE_DESCRIPTOR_SET,   // kVulkanObjectTypeDescriptorSet
+    VK_OBJECT_TYPE_DESCRIPTOR_POOL,   // kVulkanObjectTypeDescriptorPool
     VK_OBJECT_TYPE_FRAMEBUFFER,   // kVulkanObjectTypeFramebuffer
     VK_OBJECT_TYPE_COMMAND_POOL,   // kVulkanObjectTypeCommandPool
     VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,   // kVulkanObjectTypeSamplerYcbcrConversion
@@ -212,6 +215,7 @@
     VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR,   // kVulkanObjectTypeAccelerationStructureKHR
     VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL,   // kVulkanObjectTypePerformanceConfigurationINTEL
     VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV,   // kVulkanObjectTypeIndirectCommandsLayoutNV
+    VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT,   // kVulkanObjectTypePrivateDataSlotEXT
     VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA,   // kVulkanObjectTypeBufferCollectionFUCHSIA
 };
 
diff --git a/loader/loader.c b/loader/loader.c
index 6603665..7b3efec 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -70,8 +70,12 @@
 #include <initguid.h>
 #include <devpkey.h>
 #include <winternl.h>
+#include <strsafe.h>
+#include <dxgi1_6.h>
 #include "adapters.h"
-#include "dxgi_loader.h"
+
+typedef HRESULT (APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory);
+static PFN_CreateDXGIFactory1 fpCreateDXGIFactory1;
 #endif
 
 // This is a CMake generated file with #defines for any functions/includes
@@ -84,6 +88,10 @@
 // Generated file containing all the extension data
 #include "vk_loader_extensions.c"
 
+// Environment Variable information
+#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES"
+#define VK_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
+
 // Override layer information
 #define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
 
@@ -121,6 +129,14 @@
 // additionally CreateDevice and DestroyDevice needs to be locked
 loader_platform_thread_mutex loader_lock;
 loader_platform_thread_mutex loader_json_lock;
+loader_platform_thread_mutex loader_preload_icd_lock;
+
+// A list of ICDs that gets initialized when the loader does its global initialization. This list should never be used by anything
+// other than EnumerateInstanceExtensionProperties(), vkDestroyInstance, and loader_release(). This list does not change
+// functionality, but the fact that the libraries already been loaded causes any call that needs to load ICD libraries to speed up
+// significantly. This can have a huge impact when making repeated calls to vkEnumerateInstanceExtensionProperties and
+// vkCreateInstance.
+static struct loader_icd_tramp_list scanned_icds;
 
 LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
 
@@ -398,7 +414,7 @@
         } else if ((msg_type & LOADER_ERROR_BIT) != 0) {
             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
         } else if ((msg_type & LOADER_DEBUG_BIT) != 0) {
-            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
         }
 
         if ((msg_type & LOADER_PERF_BIT) != 0) {
@@ -874,7 +890,7 @@
     }
 
     if (is_driver) {
-        HRESULT hres = dyn_CreateDXGIFactory1(&IID_IDXGIFactory1, &dxgi_factory);
+        HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory1, &dxgi_factory);
         if (hres != S_OK) {
             loader_log(
                 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
@@ -1228,6 +1244,10 @@
             loader_instance_heap_free(inst, layer_list->list[i].override_paths);
             layer_list->list[i].override_paths = NULL;
         }
+        if (NULL != layer_list->list[i].app_key_paths) {
+            loader_instance_heap_free(inst, layer_list->list[i].app_key_paths);
+            layer_list->list[i].app_key_paths = NULL;
+        }
         loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_list->list[i].instance_extension_list);
         dev_ext_list = &layer_list->list[i].device_extension_list;
         if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list) {
@@ -1251,6 +1271,31 @@
     }
 }
 
+void loaderRemoveLayerInList(const struct loader_instance *inst, struct loader_layer_list *layer_list, uint32_t layer_to_remove) {
+    if (layer_list == NULL || layer_to_remove >= layer_list->count) {
+        return;
+    }
+    if (layer_list->list[layer_to_remove].type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
+        // Delete the component layers
+        loader_instance_heap_free(inst, layer_list->list[layer_to_remove].component_layer_names);
+        loader_instance_heap_free(inst, layer_list->list[layer_to_remove].override_paths);
+        loader_instance_heap_free(inst, layer_list->list[layer_to_remove].blacklist_layer_names);
+        loader_instance_heap_free(inst, layer_list->list[layer_to_remove].app_key_paths);
+    }
+
+    // Remove the current invalid meta-layer from the layer list.  Use memmove since we are
+    // overlapping the source and destination addresses.
+    memmove(&layer_list->list[layer_to_remove], &layer_list->list[layer_to_remove + 1],
+            sizeof(struct loader_layer_properties) * (layer_list->count - 1 - layer_to_remove));
+
+    // Make sure to clear out the removed layer, in case new layers are added in the previous location
+    memset(&layer_list->list[layer_list->count - 1], 0, sizeof(struct loader_layer_properties));
+
+    // Decrement the count (because we now have one less) and decrement the loop index since we need to
+    // re-check this index.
+    layer_list->count--;
+}
+
 // Remove all layers in the layer list that are blacklisted by the override layer.
 // NOTE: This should only be called if an override layer is found and not expired.
 void loaderRemoveLayersInBlacklist(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
@@ -2249,6 +2294,9 @@
     PFN_vkGetInstanceProcAddr fp_get_proc_addr;
     PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
     PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+    PFN_vk_icdEnumerateAdapterPhysicalDevices fp_enum_dxgi_adapter_phys_devs = NULL;
+#endif
     struct loader_scanned_icd *new_scanned_icd;
     uint32_t interface_vers;
     VkResult res = VK_SUCCESS;
@@ -2339,6 +2387,11 @@
             goto out;
         }
         fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+        if (interface_vers >= 6) {
+            fp_enum_dxgi_adapter_phys_devs = loader_platform_get_proc_address(handle, "vk_icdEnumerateAdapterPhysicalDevices");
+        }
+#endif
     }
 
     // check for enough capacity
@@ -2364,6 +2417,9 @@
     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;
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+    new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs;
+#endif
     new_scanned_icd->interface_version = interface_vers;
 
     new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
@@ -2432,7 +2488,7 @@
     // initialize mutexes
     loader_platform_thread_create_mutex(&loader_lock);
     loader_platform_thread_create_mutex(&loader_json_lock);
-
+    loader_platform_thread_create_mutex(&loader_preload_icd_lock);
     // initialize logging
     loader_debug_init();
 
@@ -2446,6 +2502,13 @@
     // This is needed to ensure that newer APIs are available right away
     // and not after the first call that has been statically linked
     LoadLibrary("gdi32.dll");
+
+    TCHAR systemPath[MAX_PATH] = "";
+    GetSystemDirectory(systemPath, MAX_PATH);
+    StringCchCat(systemPath, MAX_PATH, TEXT("\\dxgi.dll"));
+    HMODULE dxgi_module = LoadLibrary(systemPath);
+    fpCreateDXGIFactory1 = dxgi_module == NULL ? NULL :
+        (PFN_CreateDXGIFactory1)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
 #endif
 }
 
@@ -2456,9 +2519,38 @@
 };
 
 void loader_release() {
+    // Guarantee release of the preloaded ICD libraries. This may have already been called in vkDestroyInstance.
+    loader_unload_preloaded_icds();
+
     // release mutexes
     loader_platform_thread_delete_mutex(&loader_lock);
     loader_platform_thread_delete_mutex(&loader_json_lock);
+    loader_platform_thread_delete_mutex(&loader_preload_icd_lock);
+}
+
+// Preload the ICD libraries that are likely to be needed so we don't repeatedly load/unload them later
+void loader_preload_icds(void) {
+    loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
+
+    // Already preloaded, skip loading again.
+    if (scanned_icds.scanned_list != NULL) {
+        loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
+        return;
+    }
+
+    memset(&scanned_icds, 0, sizeof(scanned_icds));
+    VkResult result = loader_icd_scan(NULL, &scanned_icds);
+    if (result != VK_SUCCESS) {
+        loader_scanned_icd_clear(NULL, &scanned_icds);
+    }
+    loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
+}
+
+// Release the ICD libraries that were preloaded
+void loader_unload_preloaded_icds(void) {
+    loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
+    loader_scanned_icd_clear(NULL, &scanned_icds);
+    loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
 }
 
 // Get next file or dirname given a string list or registry key path
@@ -2734,6 +2826,75 @@
     }
 }
 
+// If the current working directory matches any app_key_path of the layers, remove all other override layers.
+// Otherwise if no matching app_key was found, remove all but the global override layer, which has no app_key_path.
+static void RemoveAllNonValidOverrideLayers(struct loader_instance *inst, struct loader_layer_list *instance_layers) {
+    if (instance_layers == NULL) {
+        return;
+    }
+
+    char cur_path[MAX_STRING_SIZE];
+    char *ret = loader_platform_executable_path(cur_path, sizeof(cur_path));
+    if (ret == NULL) {
+        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "RemoveAllNonValidOverrideLayers: Failed to get executable path and name");
+        return;
+    }
+
+    // Find out if there is an override layer with same the app_key_path as the path to the current executable.
+    // If more than one is found, remove it and use the first layer
+    // Remove any layers which aren't global and do not have the same app_key_path as the path to the current executable.
+    bool found_active_override_layer = false;
+    int global_layer_index = -1;
+    for (uint32_t i = 0; i < instance_layers->count; i++) {
+        struct loader_layer_properties *props = &instance_layers->list[i];
+        if (strcmp(props->info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) {
+            if (props->num_app_key_paths > 0) {  // not the global layer
+                for (uint32_t j = 0; j < props->num_app_key_paths; j++) {
+                    if (strcmp(props->app_key_paths[j], cur_path) == 0) {
+                        if (!found_active_override_layer) {
+                            found_active_override_layer = true;
+                        } else {
+                            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                                       "RemoveAllNonValidOverrideLayers: Multiple override layers where the same"
+                                       "path in app_keys was found. Using the first layer found");
+
+                            // Remove duplicate active override layers that have the same app_key_path
+                            loaderRemoveLayerInList(inst, instance_layers, i);
+                            i--;
+                        }
+                    }
+                }
+                if (!found_active_override_layer) {
+                    // Remove non-global override layers that don't have an app_key that matches cur_path
+                    loaderRemoveLayerInList(inst, instance_layers, i);
+                    i--;
+                }
+            } else {
+                if (global_layer_index == -1) {
+                    global_layer_index = i;
+                } else {
+                    loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                               "RemoveAllNonValidOverrideLayers: Multiple global override layers "
+                               "found. Using the first global layer found");
+                    loaderRemoveLayerInList(inst, instance_layers, i);
+                    i--;
+                }
+            }
+        }
+    }
+    // Remove global layer if layer with same the app_key_path as the path to the current executable is found
+    if (found_active_override_layer && global_layer_index >= 0) {
+        loaderRemoveLayerInList(inst, instance_layers, global_layer_index);
+    }
+    // Should be at most 1 override layer in the list now.
+    if (found_active_override_layer) {
+        loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Using the override layer for app key %s", cur_path);
+    } else if (global_layer_index >= 0) {
+        loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Using the global override layer");
+    }
+}
+
 // This structure is used to store the json file version
 // in a more manageable way.
 typedef struct {
@@ -3135,6 +3296,7 @@
     char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
     char *spec_version = NULL;
     char **entry_array = NULL;
+    cJSON *app_keys = NULL;
 
     // Layer interface functions
     //    vkGetInstanceProcAddr
@@ -3323,6 +3485,45 @@
         }
     }
 
+    props->num_app_key_paths = 0;
+    props->app_key_paths = NULL;
+    app_keys = cJSON_GetObjectItem(layer_node, "app_keys");
+    if (app_keys != NULL) {
+        if (strcmp(name, VK_OVERRIDE_LAYER_NAME)) {
+            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                       "Layer %s contains app_keys, but any app_keys can only be provided by the override metalayer. "
+                       "These will be ignored.",
+                       name);
+        } else {
+            props->num_app_key_paths = cJSON_GetArraySize(app_keys);
+
+            // Allocate the blacklist array
+            props->app_key_paths = loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * props->num_app_key_paths,
+                                                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+            if (props->app_key_paths == NULL) {
+                result = VK_ERROR_OUT_OF_HOST_MEMORY;
+                goto out;
+            }
+
+            // Copy the app_key_paths into the array
+            for (i = 0; i < (int)props->num_app_key_paths; ++i) {
+                cJSON *app_key_path = cJSON_GetArrayItem(app_keys, i);
+                if (app_key_path == NULL) {
+                    continue;
+                }
+                temp = cJSON_Print(app_key_path);
+                if (temp == NULL) {
+                    result = VK_ERROR_OUT_OF_HOST_MEMORY;
+                    goto out;
+                }
+                temp[strlen(temp) - 1] = '\0';
+                strncpy(props->app_key_paths[i], temp + 1, MAX_STRING_SIZE - 1);
+                props->app_key_paths[i][MAX_STRING_SIZE - 1] = '\0';
+                cJSON_Free(temp);
+            }
+        }
+    }
+
     result = VK_SUCCESS;
 
 out:
@@ -3339,12 +3540,17 @@
         if (NULL != props->override_paths) {
             loader_instance_heap_free(inst, props->override_paths);
         }
+        if (NULL != props->app_key_paths) {
+            loader_instance_heap_free(inst, props->app_key_paths);
+        }
         props->num_blacklist_layers = 0;
         props->blacklist_layer_names = NULL;
         props->num_component_layers = 0;
         props->component_layer_names = NULL;
         props->num_override_paths = 0;
         props->override_paths = NULL;
+        props->num_app_key_paths = 0;
+        props->app_key_paths = NULL;
     }
 
     return result;
@@ -3607,7 +3813,7 @@
 }
 
 static VkResult AddDataFilesInPath(const struct loader_instance *inst, char *search_path, bool is_directory_list,
-                                   struct loader_data_files *out_files) {
+                                   struct loader_data_files *out_files, bool use_first_found_manifest) {
     VkResult vk_result = VK_SUCCESS;
     DIR *dir_stream = NULL;
     struct dirent *dir_entry;
@@ -3689,6 +3895,9 @@
                 break;
             }
         }
+        if (use_first_found_manifest && out_files->count > 0) {
+            break;
+        }
     }
 
 out:
@@ -3710,6 +3919,7 @@
     char *search_path = NULL;
     char *cur_path_ptr = NULL;
     size_t rel_size = 0;
+    bool use_first_found_manifest = false;
 #ifndef _WIN32
     bool xdgconfig_alloc = true;
     bool xdgdata_alloc = true;
@@ -3841,6 +4051,10 @@
                         memcpy(cur_path_ptr, relative_location, rel_size);
                         cur_path_ptr += rel_size;
                         *cur_path_ptr++ = PATH_SEPARATOR;
+                        // only for ICD manifests
+                        if (env_override != NULL && strcmp(VK_ICD_FILENAMES_ENV_VAR, env_override) == 0) {
+                            use_first_found_manifest = true;
+                        }
                     }
                     CFRelease(ref);
                 }
@@ -3866,6 +4080,39 @@
 #endif
     }
 
+    // Remove duplicate paths, or it would result in duplicate extensions, duplicate devices, etc.
+    // This uses minimal memory, but is O(N^2) on the number of paths. Expect only a few paths.
+    char path_sep_str[2] = {PATH_SEPARATOR, '\0'};
+    size_t search_path_updated_size = strlen(search_path);
+    for (size_t first = 0; first < search_path_updated_size;) {
+        // If this is an empty path, erase it
+        if (search_path[first] == PATH_SEPARATOR) {
+            memmove(&search_path[first], &search_path[first + 1], search_path_updated_size - first + 1);
+            search_path_updated_size -= 1;
+            continue;
+        }
+
+        size_t first_end = first + 1;
+        first_end += strcspn(&search_path[first_end], path_sep_str);
+        for (size_t second = first_end + 1; second < search_path_updated_size;) {
+            size_t second_end = second + 1;
+            second_end += strcspn(&search_path[second_end], path_sep_str);
+            if (first_end - first == second_end - second &&
+                !strncmp(&search_path[first], &search_path[second], second_end - second)) {
+                // Found duplicate. Include PATH_SEPARATOR in second_end, then erase it from search_path.
+                if (search_path[second_end] == PATH_SEPARATOR) {
+                    second_end++;
+                }
+                memmove(&search_path[second], &search_path[second_end], search_path_updated_size - second_end + 1);
+                search_path_updated_size -= second_end - second;
+            } else {
+                second = second_end + 1;
+            }
+        }
+        first = first_end + 1;
+    }
+    search_path_size = search_path_updated_size;
+
     // Print out the paths being searched if debugging is enabled
     if (search_path_size > 0) {
         loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
@@ -3873,7 +4120,7 @@
     }
 
     // Now, parse the paths and add any manifest files found in them.
-    vk_result = AddDataFilesInPath(inst, search_path, is_directory_list, out_files);
+    vk_result = AddDataFilesInPath(inst, search_path, is_directory_list, out_files, use_first_found_manifest);
 
     if (NULL != override_path) {
         *override_active = true;
@@ -4109,7 +4356,7 @@
     }
 
     // Now, parse the paths and add any manifest files found in them.
-    vk_result = AddDataFilesInPath(inst, search_path, false, out_files);
+    vk_result = AddDataFilesInPath(inst, search_path, false, out_files, false);
 
 out:
 
@@ -4229,14 +4476,12 @@
     if (VK_SUCCESS != res) {
         goto out;
     }
-
     // Get a list of manifest files for ICDs
-    res = loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_ICD, true, "VK_ICD_FILENAMES", NULL, VK_DRIVERS_INFO_REGISTRY_LOC,
-                             VK_DRIVERS_INFO_RELATIVE_DIR, &manifest_files);
+    res = loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_ICD, true, VK_ICD_FILENAMES_ENV_VAR, NULL,
+                             VK_DRIVERS_INFO_REGISTRY_LOC, VK_DRIVERS_INFO_RELATIVE_DIR, &manifest_files);
     if (VK_SUCCESS != res || manifest_files.count == 0) {
         goto out;
     }
-
     loader_platform_thread_lock_mutex(&loader_json_lock);
     lockedMutex = true;
     for (uint32_t i = 0; i < manifest_files.count; i++) {
@@ -4257,6 +4502,7 @@
                 res = temp_res;
             }
             if (temp_res == VK_ERROR_OUT_OF_HOST_MEMORY) {
+                res = VK_ERROR_OUT_OF_HOST_MEMORY;
                 break;
             } else {
                 continue;
@@ -4506,6 +4752,9 @@
         }
     }
 
+    // Remove any extraneous override layers.
+    RemoveAllNonValidOverrideLayers(inst, instance_layers);
+
     // Check to see if the override layer is present, and use it's override paths.
     for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
         struct loader_layer_properties *prop = &instance_layers->list[i];
@@ -4533,7 +4782,7 @@
     }
 
     // Get a list of manifest files for explicit layers
-    if (VK_SUCCESS != loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, "VK_LAYER_PATH", override_paths,
+    if (VK_SUCCESS != loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, VK_LAYER_PATH_ENV_VAR, override_paths,
                                          VK_ELAYERS_INFO_REGISTRY_LOC, VK_ELAYERS_INFO_RELATIVE_DIR, &manifest_files)) {
         goto out;
     }
@@ -4645,6 +4894,9 @@
         }
     }
 
+    // Remove any extraneous override layers.
+    RemoveAllNonValidOverrideLayers(inst, instance_layers);
+
     // Check to see if either the override layer is present, or another implicit meta-layer.
     // Each of these may require explicit layers to be enabled at this time.
     for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
@@ -4681,7 +4933,7 @@
     // explicit layer info as well.  Not to worry, though, all explicit layers not included
     // in the override layer will be removed below in loaderRemoveLayersInBlacklist().
     if (override_layer_valid || implicit_metalayer_present) {
-        if (VK_SUCCESS != loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, "VK_LAYER_PATH", override_paths,
+        if (VK_SUCCESS != loaderGetDataFiles(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, VK_LAYER_PATH_ENV_VAR, override_paths,
                                              VK_ELAYERS_INFO_REGISTRY_LOC, VK_ELAYERS_INFO_RELATIVE_DIR, &manifest_files)) {
             goto out;
         }
@@ -5763,28 +6015,46 @@
         }
     }
 
+    VkLoaderFeatureFlags feature_flags = 0;
+#if defined(_WIN32)
+    IDXGIFactory6* dxgi_factory = NULL;
+    HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory6, &dxgi_factory);
+    if (hres == S_OK) {
+        feature_flags |= VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING;
+        dxgi_factory->lpVtbl->Release(dxgi_factory);
+    }
+#endif
+
     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
     if (fpCreateInstance) {
-        VkLayerInstanceCreateInfo create_info_disp;
-
-        create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
-        create_info_disp.function = VK_LOADER_DATA_CALLBACK;
-
-        create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
-
-        create_info_disp.pNext = loader_create_info.pNext;
-        loader_create_info.pNext = &create_info_disp;
-
-        VkLayerInstanceCreateInfo create_info_disp2;
-
-        create_info_disp2.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
-        create_info_disp2.function = VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK;
-
-        create_info_disp2.u.layerDevice.pfnLayerCreateDevice = loader_layer_create_device;
-        create_info_disp2.u.layerDevice.pfnLayerDestroyDevice = loader_layer_destroy_device;
-
-        create_info_disp2.pNext = loader_create_info.pNext;
-        loader_create_info.pNext = &create_info_disp2;
+        const VkLayerInstanceCreateInfo instance_dispatch = {
+            .sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,
+            .pNext = loader_create_info.pNext,
+            .function = VK_LOADER_DATA_CALLBACK,
+            .u = {
+                .pfnSetInstanceLoaderData = vkSetInstanceDispatch,
+            },
+        };
+        const VkLayerInstanceCreateInfo device_callback = {
+            .sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,
+            .pNext = &instance_dispatch,
+            .function = VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK,
+            .u = {
+                .layerDevice = {
+                    .pfnLayerCreateDevice = loader_layer_create_device,
+                    .pfnLayerDestroyDevice = loader_layer_destroy_device,
+                },
+            },
+        };
+        const VkLayerInstanceCreateInfo loader_features = {
+            .sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,
+            .pNext = &device_callback,
+            .function = VK_LOADER_FEATURES,
+            .u = {
+                .loaderFeatures = feature_flags,
+            },
+        };
+        loader_create_info.pNext = &loader_features;
 
         res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
     } else {
@@ -6758,11 +7028,136 @@
     return res;
 }
 
+struct LoaderSortedPhysicalDevice {
+    uint32_t device_count;
+    VkPhysicalDevice* physical_devices;
+    uint32_t icd_index;
+    struct loader_icd_term* icd_term;
+};
+
+// This function allocates an array in sorted_devices which must be freed by the caller if not null
+VkResult ReadSortedPhysicalDevices(struct loader_instance *inst, struct LoaderSortedPhysicalDevice **sorted_devices, uint32_t* sorted_count)
+{
+    VkResult res = VK_SUCCESS;
+#if defined(_WIN32)
+    uint32_t sorted_alloc = 0;
+    struct loader_icd_term* icd_term = NULL;
+
+    IDXGIFactory6* dxgi_factory = NULL;
+    HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory6, &dxgi_factory);
+    if (hres != S_OK) {
+        loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Failed to create DXGI factory 6. Physical devices will not be sorted");
+    }
+    else {
+        sorted_alloc = 16;
+        *sorted_devices = loader_instance_heap_alloc(inst, sorted_alloc * sizeof(struct LoaderSortedPhysicalDevice), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+        if (*sorted_devices == NULL) {
+            res = VK_ERROR_OUT_OF_HOST_MEMORY;
+            goto out;
+        }
+
+        memset(*sorted_devices, 0, sorted_alloc * sizeof(struct LoaderSortedPhysicalDevice));
+
+        *sorted_count = 0;
+        for (uint32_t i = 0; ; ++i) {
+            IDXGIAdapter1* adapter;
+            hres = dxgi_factory->lpVtbl->EnumAdapterByGpuPreference(dxgi_factory, i, DXGI_GPU_PREFERENCE_UNSPECIFIED, &IID_IDXGIAdapter1, &adapter);
+            if (hres == DXGI_ERROR_NOT_FOUND) {
+                break; // No more adapters
+            }
+            else if (hres != S_OK) {
+                loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Failed to enumerate adapters by GPU preference at index %u. This adapter will not be sorted", i);
+                break;
+            }
+
+            DXGI_ADAPTER_DESC1 description;
+            hres = adapter->lpVtbl->GetDesc1(adapter, &description);
+            if (hres != S_OK) {
+                loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Failed to get adapter LUID index %u. This adapter will not be sorted", i);
+                continue;
+            }
+
+            if (sorted_alloc <= i) {
+                uint32_t old_size = sorted_alloc * sizeof(struct LoaderSortedPhysicalDevice);
+                *sorted_devices = loader_instance_heap_realloc(inst, *sorted_devices, old_size, 2 * old_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+                if (*sorted_devices == NULL) {
+                    adapter->lpVtbl->Release(adapter);
+                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
+                    goto out;
+                }
+                sorted_alloc *= 2;
+            }
+            struct LoaderSortedPhysicalDevice *sorted_array = *sorted_devices;
+            sorted_array[*sorted_count].device_count = 0;
+            sorted_array[*sorted_count].physical_devices = NULL;
+            //*sorted_count = i;
+
+            icd_term = inst->icd_terms;
+            for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
+                // This is the new behavior, which cannot be run unless the ICD provides EnumerateAdapterPhysicalDevices
+                if (icd_term->scanned_icd->EnumerateAdapterPhysicalDevices == NULL) {
+                    continue;
+                }
+
+                uint32_t count;
+                VkResult vkres = icd_term->scanned_icd->EnumerateAdapterPhysicalDevices(icd_term->instance, description.AdapterLuid, &count, NULL);
+                if (vkres == VK_ERROR_INCOMPATIBLE_DRIVER) {
+                    continue; // This driver doesn't support the adapter
+                }
+                else if (vkres != VK_SUCCESS) {
+                    loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Failed to convert DXGI adapter into Vulkan physical device with unexpected error code");
+                    continue;
+                }
+
+                // Get the actual physical devices
+                if (0 != count)
+                {
+                    do {
+                        sorted_array[*sorted_count].physical_devices = loader_instance_heap_realloc(inst, sorted_array[*sorted_count].physical_devices, sorted_array[*sorted_count].device_count * sizeof(VkPhysicalDevice), count * sizeof(VkPhysicalDevice), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+                        if (sorted_array[*sorted_count].physical_devices == NULL) {
+                            res = VK_ERROR_OUT_OF_HOST_MEMORY;
+                            break;
+                        }
+                        sorted_array[*sorted_count].device_count = count;
+                    } while (vkres = icd_term->scanned_icd->EnumerateAdapterPhysicalDevices(icd_term->instance, description.AdapterLuid, &count, sorted_array[*sorted_count].physical_devices) == VK_INCOMPLETE);
+                }
+
+                if (vkres != VK_SUCCESS) {
+                    loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Failed to convert DXGI adapter into Vulkan physical device");
+                    continue;
+                }
+                else if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
+                    goto out;
+                }
+                inst->total_gpu_count += (sorted_array[*sorted_count].device_count = count);
+                sorted_array[*sorted_count].icd_index = icd_idx;
+                sorted_array[*sorted_count].icd_term = icd_term;
+                ++(*sorted_count);
+            }
+
+            adapter->lpVtbl->Release(adapter);
+        }
+
+        dxgi_factory->lpVtbl->Release(dxgi_factory);
+    }
+
+out:
+#endif
+
+    if (*sorted_count == 0 && *sorted_devices != NULL) {
+        loader_instance_heap_free(inst, *sorted_devices);
+        *sorted_devices = NULL;
+    }
+    return res;
+}
+
 VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
     VkResult res = VK_SUCCESS;
     struct loader_icd_term *icd_term;
     struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
     struct loader_physical_device_term **new_phys_devs = NULL;
+    struct LoaderSortedPhysicalDevice *sorted_phys_dev_array = NULL;
+    uint32_t sorted_count = 0;
 
     inst->total_gpu_count = 0;
 
@@ -6779,11 +7174,28 @@
         goto out;
     }
     memset(icd_phys_dev_array, 0, sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
-    icd_term = inst->icd_terms;
+
+    // Get the physical devices supported by platform sorting mechanism into a separate list
+    res = ReadSortedPhysicalDevices(inst, &sorted_phys_dev_array, &sorted_count);
+    if (VK_SUCCESS != res) {
+        goto out;
+    }
 
     // For each ICD, query the number of physical devices, and then get an
     // internal value for those physical devices.
+    icd_term = inst->icd_terms;
     for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
+        icd_phys_dev_array[icd_idx].count = 0;
+        icd_phys_dev_array[icd_idx].phys_devs = NULL;
+        icd_phys_dev_array[icd_idx].this_icd_term = NULL;
+
+        // This is the legacy behavior which should be skipped if EnumerateAdapterPhysicalDevices is available
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+        if (icd_term->scanned_icd->EnumerateAdapterPhysicalDevices != NULL) {
+            continue;
+        }
+#endif
+
         res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].count, NULL);
         if (VK_SUCCESS != res) {
             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
@@ -6836,6 +7248,49 @@
 
     // Copy or create everything to fill the new array of physical devices
     uint32_t idx = 0;
+
+#if defined(_WIN32)
+    // Copy over everything found through sorted enumeration
+    for (uint32_t i = 0; i < sorted_count; ++i) {
+        for (uint32_t j = 0; j < sorted_phys_dev_array[i].device_count; ++i) {
+
+            // Check if this physical device is already in the old buffer
+            if (NULL != inst->phys_devs_term) {
+                for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
+                    if (sorted_phys_dev_array[i].physical_devices[j] == inst->phys_devs_term[old_idx]->phys_dev) {
+                        new_phys_devs[idx] = inst->phys_devs_term[old_idx];
+                        break;
+                    }
+                }
+            }
+
+            // If this physical device isn't in the old buffer, then we need to create it.
+            if (NULL == new_phys_devs[idx]) {
+                new_phys_devs[idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term),
+                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+                if (NULL == new_phys_devs[idx]) {
+                    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                        "setupLoaderTermPhysDevs:  Failed to allocate "
+                        "physical device terminator object %d",
+                        idx);
+                    inst->total_gpu_count = idx;
+                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
+                    goto out;
+                }
+
+                loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
+                new_phys_devs[idx]->this_icd_term = sorted_phys_dev_array[i].icd_term;
+                new_phys_devs[idx]->icd_index = (uint8_t)(sorted_phys_dev_array[i].icd_index);
+                new_phys_devs[idx]->phys_dev = sorted_phys_dev_array[i].physical_devices[j];
+            }
+
+            // Increment the count of new physical devices
+            idx++;
+        }
+    }
+#endif
+
+    // Copy over everything found through EnumeratePhysicalDevices
     for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
         for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count; pd_idx++) {
             // Check if this physical device is already in the old buffer
@@ -6907,6 +7362,15 @@
         inst->phys_devs_term = new_phys_devs;
     }
 
+    if (sorted_phys_dev_array != NULL) {
+        for (uint32_t i = 0; i < sorted_count; ++i) {
+            if (sorted_phys_dev_array[i].device_count > 0 && sorted_phys_dev_array[i].physical_devices != NULL) {
+                loader_instance_heap_free(inst, sorted_phys_dev_array[i].physical_devices);
+            }
+        }
+        loader_instance_heap_free(inst, sorted_phys_dev_array);
+    }
+
     return res;
 }
 
@@ -7050,7 +7514,6 @@
             if (pProperties == NULL) {
                 *pPropertyCount = count;
                 loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list);
-                loader_platform_thread_unlock_mutex(&loader_lock);
                 return VK_SUCCESS;
             }
 
@@ -7062,14 +7525,12 @@
 
             loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list);
             if (copy_size < count) {
-                loader_platform_thread_unlock_mutex(&loader_lock);
                 return VK_INCOMPLETE;
             }
         } else {
             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                        "vkEnumerateDeviceExtensionProperties:  pLayerName "
                        "is too long or is badly formed");
-            loader_platform_thread_unlock_mutex(&loader_lock);
             return VK_ERROR_EXTENSION_NOT_PRESENT;
         }
 
@@ -7285,10 +7746,14 @@
             }
         }
     } else {
+        // Preload ICD libraries so subsequent calls to EnumerateInstanceExtensionProperties don't have to load them
+        loader_preload_icds();
+
         // Scan/discover all ICD libraries
         memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
         res = loader_icd_scan(NULL, &icd_tramp_list);
-        if (VK_SUCCESS != res) {
+        // EnumerateInstanceExtensionProperties can't return anything other than OOM or VK_ERROR_LAYER_NOT_PRESENT
+        if ((VK_SUCCESS != res && icd_tramp_list.count > 0) || res == VK_ERROR_OUT_OF_HOST_MEMORY) {
             goto out;
         }
         // Get extensions from all ICD's, merge so no duplicates
@@ -7409,7 +7874,10 @@
     uint32_t cur_icd_group_count = 0;
     VkPhysicalDeviceGroupPropertiesKHR **new_phys_dev_groups = NULL;
     VkPhysicalDeviceGroupPropertiesKHR *local_phys_dev_groups = NULL;
+    bool *local_phys_dev_group_sorted = NULL;
     PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL;
+    struct LoaderSortedPhysicalDevice* sorted_phys_dev_array = NULL;
+    uint32_t sorted_count = 0;
 
     if (0 == inst->phys_dev_count_term) {
         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
@@ -7473,7 +7941,8 @@
     // Create a temporary array (on the stack) to keep track of the
     // returned VkPhysicalDevice values.
     local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupProperties) * total_count);
-    if (NULL == local_phys_dev_groups) {
+    local_phys_dev_group_sorted = loader_stack_alloc(sizeof(bool) * total_count);
+    if (NULL == local_phys_dev_groups || NULL == local_phys_dev_group_sorted) {
         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
             "setupLoaderTermPhysDevGroups:  Failed to allocate local "
             "physical device group array of size %d",
@@ -7483,17 +7952,31 @@
     }
     // Initialize the memory to something valid
     memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupProperties) * total_count);
+    memset(local_phys_dev_group_sorted, 0, sizeof(bool) * total_count);
     for (uint32_t group = 0; group < total_count; group++) {
         local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR;
         local_phys_dev_groups[group].pNext = NULL;
         local_phys_dev_groups[group].subsetAllocation = false;
     }
 
+    // Get the physical devices supported by platform sorting mechanism into a separate list
+    res = ReadSortedPhysicalDevices(inst, &sorted_phys_dev_array, &sorted_count);
+    if (VK_SUCCESS != res) {
+        goto out;
+    }
+
     cur_icd_group_count = 0;
     icd_term = inst->icd_terms;
     for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
         uint32_t count_this_time = total_count - cur_icd_group_count;
 
+        // Check if this group can be sorted
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+        bool icd_sorted = icd_term->scanned_icd->EnumerateAdapterPhysicalDevices != NULL;
+#else
+        bool icd_sorted = false;
+#endif
+
         // Get the function pointer to use to call into the ICD. This could be the core or KHR version
         if (inst->enabled_known_extensions.khr_device_group_creation) {
             fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
@@ -7525,10 +8008,14 @@
             for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
                 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDeviceCount = 1;
                 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDevices[0] = phys_dev_array[indiv_gpu];
+                local_phys_dev_group_sorted[indiv_gpu + cur_icd_group_count] = icd_sorted;
             }
 
         } else {
             res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, &local_phys_dev_groups[cur_icd_group_count]);
+            for (uint32_t group = 0; group < count_this_time; ++group) {
+                local_phys_dev_group_sorted[group + cur_icd_group_count] = icd_sorted;
+            }
             if (VK_SUCCESS != res) {
                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                     "setupLoaderTermPhysDevGroups:  Failed during dispatch call of "
@@ -7563,8 +8050,87 @@
         }
     }
 
+    uint32_t idx = 0;
+
+#if defined(_WIN32)
+    // Copy over everything found through sorted enumeration
+    for (uint32_t i = 0; i < sorted_count; ++i) {
+
+        // Find the VkPhysicalDeviceGroupProperties object in local_phys_dev_groups
+        VkPhysicalDeviceGroupProperties *group_properties = NULL;
+        for (uint32_t group = 0; group < total_count; group++) {
+            if (sorted_phys_dev_array[i].device_count != local_phys_dev_groups[group].physicalDeviceCount) {
+                continue;
+            }
+
+            bool match = true;
+            for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
+                if (sorted_phys_dev_array[i].physical_devices[group_gpu] != ((struct loader_physical_device_term*) local_phys_dev_groups[group].physicalDevices[group_gpu])->phys_dev) {
+                    match = false;
+                    break;
+                }
+            }
+
+            if (match) {
+                group_properties = &local_phys_dev_groups[group];
+            }
+        }
+
+        // Check if this physical device group with the same contents is already in the old buffer
+        for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
+            if (NULL != group_properties && group_properties->physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
+                bool found_all_gpus = true;
+                for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
+                    bool found_gpu = false;
+                    for (uint32_t new_gpu = 0; new_gpu < group_properties->physicalDeviceCount; new_gpu++) {
+                        if (group_properties->physicalDevices[new_gpu] == inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
+                            found_gpu = true;
+                            break;
+                        }
+                    }
+
+                    if (!found_gpu) {
+                        found_all_gpus = false;
+                        break;
+                    }
+                }
+                if (!found_all_gpus) {
+                    continue;
+                }
+                else {
+                    new_phys_dev_groups[idx] = inst->phys_dev_groups_term[old_idx];
+                    break;
+                }
+            }
+        }
+
+        // If this physical device group isn't in the old buffer, create it
+        if (group_properties != NULL && NULL == new_phys_dev_groups[idx]) {
+            new_phys_dev_groups[idx] = (VkPhysicalDeviceGroupPropertiesKHR*)loader_instance_heap_alloc(
+                inst, sizeof(VkPhysicalDeviceGroupPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+            if (NULL == new_phys_dev_groups[idx]) {
+                loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                    "setupLoaderTermPhysDevGroups:  Failed to allocate "
+                    "physical device group Terminator object %d",
+                    idx);
+                total_count = idx;
+                res = VK_ERROR_OUT_OF_HOST_MEMORY;
+                goto out;
+            }
+            memcpy(new_phys_dev_groups[idx], group_properties, sizeof(VkPhysicalDeviceGroupPropertiesKHR));
+        }
+
+        ++idx;
+    }
+#endif
+
     // Copy or create everything to fill the new array of physical device groups
     for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
+        // Skip groups which have been included through sorting
+        if (local_phys_dev_group_sorted[new_idx] || local_phys_dev_groups[new_idx].physicalDeviceCount == 0) {
+            continue;
+        }
+
         // Check if this physical device group with the same contents is already in the old buffer
         for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
             if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
@@ -7586,28 +8152,30 @@
                 if (!found_all_gpus) {
                     continue;
                 } else {
-                    new_phys_dev_groups[new_idx] = inst->phys_dev_groups_term[old_idx];
+                    new_phys_dev_groups[idx] = inst->phys_dev_groups_term[old_idx];
                     break;
                 }
             }
         }
 
         // If this physical device group isn't in the old buffer, create it
-        if (NULL == new_phys_dev_groups[new_idx]) {
-            new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHR *)loader_instance_heap_alloc(
+        if (NULL == new_phys_dev_groups[idx]) {
+            new_phys_dev_groups[idx] = (VkPhysicalDeviceGroupPropertiesKHR *)loader_instance_heap_alloc(
                 inst, sizeof(VkPhysicalDeviceGroupPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-            if (NULL == new_phys_dev_groups[new_idx]) {
+            if (NULL == new_phys_dev_groups[idx]) {
                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
                     "setupLoaderTermPhysDevGroups:  Failed to allocate "
                     "physical device group Terminator object %d",
-                    new_idx);
-                total_count = new_idx;
+                    idx);
+                total_count = idx;
                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
                 goto out;
             }
-            memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
+            memcpy(new_phys_dev_groups[idx], &local_phys_dev_groups[new_idx],
                 sizeof(VkPhysicalDeviceGroupPropertiesKHR));
         }
+
+        ++idx;
     }
 
 out:
@@ -7644,6 +8212,15 @@
         inst->phys_dev_groups_term = new_phys_dev_groups;
     }
 
+    if (sorted_phys_dev_array != NULL) {
+        for (uint32_t i = 0; i < sorted_count; ++i) {
+            if (sorted_phys_dev_array[i].device_count > 0 && sorted_phys_dev_array[i].physical_devices != NULL) {
+                loader_instance_heap_free(inst, sorted_phys_dev_array[i].physical_devices);
+            }
+        }
+        loader_instance_heap_free(inst, sorted_phys_dev_array);
+    }
+
     return res;
 }
 
diff --git a/loader/loader.h b/loader/loader.h
index e346912..0ef8cf6 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -156,6 +156,8 @@
     bool keep;
     uint32_t num_blacklist_layers;
     char (*blacklist_layer_names)[MAX_STRING_SIZE];
+    uint32_t num_app_key_paths;
+    char (*app_key_paths)[MAX_STRING_SIZE];
 };
 
 struct loader_layer_list {
@@ -324,6 +326,9 @@
 #ifdef VK_USE_PLATFORM_XLIB_KHR
     bool wsi_xlib_surface_enabled;
 #endif
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    bool wsi_directfb_surface_enabled;
+#endif
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     bool wsi_android_surface_enabled;
 #endif
@@ -385,6 +390,9 @@
     PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;
     PFN_vkCreateInstance CreateInstance;
     PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
+#if defined(VK_USE_PLATFORM_WIN32_KHR)
+    PFN_vk_icdEnumerateAdapterPhysicalDevices EnumerateAdapterPhysicalDevices;
+#endif
 };
 
 static inline struct loader_instance *loader_instance(VkInstance instance) { return (struct loader_instance *)instance; }
@@ -425,6 +433,7 @@
 extern THREAD_LOCAL_DECL struct loader_instance *tls_instance;
 extern loader_platform_thread_mutex loader_lock;
 extern loader_platform_thread_mutex loader_json_lock;
+extern loader_platform_thread_mutex loader_preload_icd_lock;
 
 struct loader_msg_callback_map_entry {
     VkDebugReportCallbackEXT icd_obj;
@@ -455,6 +464,8 @@
                                              const VkInstanceCreateInfo *pCreateInfo);
 
 void loader_initialize(void);
+void loader_preload_icds(void);
+void loader_unload_preloaded_icds(void);
 bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
                                      const VkExtensionProperties *ext_array);
 bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list);
diff --git a/loader/trampoline.c b/loader/trampoline.c
index b78638e..44d9795 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -656,9 +656,14 @@
                                          ptr_instance->tmp_report_callbacks);
         util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks);
     }
+
     loader_instance_heap_free(ptr_instance, ptr_instance->disp);
     loader_instance_heap_free(ptr_instance, ptr_instance);
     loader_platform_thread_unlock_mutex(&loader_lock);
+
+    // Unload preloaded layers, so if vkEnumerateInstanceExtensionProperties or vkCreateInstance is called again, the ICD's are up
+    // to date
+    loader_unload_preloaded_icds();
 }
 
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
@@ -859,7 +864,9 @@
     disp = loader_get_dispatch(device);
 
     disp->GetDeviceQueue(device, queueNodeIndex, queueIndex, pQueue);
-    loader_set_dispatch(*pQueue, disp);
+    if (pQueue != NULL) {
+        loader_set_dispatch(*pQueue, disp);
+    }
 }
 
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
@@ -2445,8 +2452,7 @@
 LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
     const VkLayerDispatchTable *disp = loader_get_dispatch(device);
     disp->GetDeviceQueue2(device, pQueueInfo, pQueue);
-    if (*pQueue != VK_NULL_HANDLE)
-    {
+    if (pQueue != NULL && *pQueue != NULL) {
         loader_set_dispatch(*pQueue, disp);
     }
 }
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index 2913f7e..026665f 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -42,7 +42,6 @@
 //#ifndef _GNU_SOURCE
 //#define _GNU_SOURCE 1
 //#endif
-// TBD: Are the contents of the following file used?
 #include <unistd.h>
 // Note: The following file is for dynamic loading:
 #include <dlfcn.h>
@@ -104,6 +103,36 @@
 
 static inline char *loader_platform_dirname(char *path) { return dirname(path); }
 
+#if defined(__linux__) || defined(__Fuchsia__)
+
+// find application path + name. Path cannot be longer than 1024, returns NULL if it is greater than that.
+static inline char *loader_platform_executable_path(char *buffer, size_t size) {
+    ssize_t count = readlink("/proc/self/exe", buffer, size);
+    if (count == -1) return NULL;
+    if (count == 0) return NULL;
+    buffer[count] = '\0';
+    return buffer;
+}
+#elif defined(__APPLE__)  // defined(__linux__)
+#include <libproc.h>
+static inline char *loader_platform_executable_path(char *buffer, size_t size) {
+    pid_t pid = getpid();
+    int ret = proc_pidpath(pid, buffer, size);
+    if (ret <= 0) return NULL;
+    buffer[ret] = '\0';
+    return buffer;
+}
+#endif  // defined (__APPLE__)
+
+// Compatability with compilers that don't support __has_feature
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+#define LOADER_ADDRESS_SANITIZER
+#endif
+
 // Dynamic Loading of libraries:
 typedef void *loader_platform_dl_handle;
 static inline loader_platform_dl_handle loader_platform_open_library_or_driver(const char *libPath, bool driver) {
@@ -179,6 +208,7 @@
 #include <io.h>
 #include <stdbool.h>
 #include <shlwapi.h>
+#include <direct.h>
 #ifdef __cplusplus
 #include <iostream>
 #include <string>
@@ -296,6 +326,14 @@
     return path;
 }
 
+static inline char *loader_platform_executable_path(char *buffer, size_t size) {
+    DWORD ret = GetModuleFileName(NULL, buffer, (DWORD)size);
+    if (ret == 0) return NULL;
+    if (ret > size) return NULL;
+    buffer[ret] = '\0';
+    return buffer;
+}
+
 // Dynamic Loading:
 typedef HMODULE loader_platform_dl_handle;
 static loader_platform_dl_handle loader_platform_open_library(const char *lib_path) {
diff --git a/loader/wsi.c b/loader/wsi.c
index 9c6a1d5..0d687b2 100644
--- a/loader/wsi.c
+++ b/loader/wsi.c
@@ -52,6 +52,9 @@
 #ifdef VK_USE_PLATFORM_XLIB_KHR
     ptr_instance->wsi_xlib_surface_enabled = false;
 #endif  // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+    ptr_instance->wsi_directfb_surface_enabled = false;
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     ptr_instance->wsi_android_surface_enabled = false;
 #endif  // VK_USE_PLATFORM_ANDROID_KHR
@@ -99,6 +102,12 @@
             continue;
         }
 #endif  // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME) == 0) {
+            ptr_instance->wsi_directfb_surface_enabled = true;
+            continue;
+        }
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
             ptr_instance->wsi_android_surface_enabled = true;
@@ -163,6 +172,9 @@
 #ifndef VK_USE_PLATFORM_XLIB_KHR
     if (!strcmp(ext_prop->extensionName, "VK_KHR_xlib_surface")) return true;
 #endif  // VK_USE_PLATFORM_XLIB_KHR
+#ifndef VK_USE_PLATFORM_DIRECTFB_EXT
+    if (!strcmp(ext_prop->extensionName, "VK_EXT_directfb_surface")) return true;
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
 
     return false;
 }
@@ -951,6 +963,124 @@
 }
 #endif  // VK_USE_PLATFORM_XLIB_KHR
 
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+
+// Functions for the VK_EXT_directfb_surface extension:
+
+// This is the trampoline entrypoint for CreateDirectFBSurfaceEXT
+LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT(VkInstance instance,
+                                                                        const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo,
+                                                                        const VkAllocationCallbacks *pAllocator,
+                                                                        VkSurfaceKHR *pSurface) {
+    const VkLayerInstanceDispatchTable *disp;
+    disp = loader_get_instance_layer_dispatch(instance);
+    VkResult res;
+
+    res = disp->CreateDirectFBSurfaceEXT(instance, pCreateInfo, pAllocator, pSurface);
+    return res;
+}
+
+// This is the instance chain terminator function for CreateDirectFBSurfaceEXT
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDirectFBSurfaceEXT(VkInstance instance,
+                                                                   const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo,
+                                                                   const VkAllocationCallbacks *pAllocator,
+                                                                   VkSurfaceKHR *pSurface) {
+    VkResult vkRes = VK_SUCCESS;
+    VkIcdSurface *pIcdSurface = NULL;
+    uint32_t i = 0;
+
+    // First, check to ensure the appropriate extension was enabled:
+    struct loader_instance *ptr_instance = loader_get_instance(instance);
+    if (!ptr_instance->wsi_directfb_surface_enabled) {
+        loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "VK_EXT_directfb_surface extension not enabled.  vkCreateDirectFBSurfaceEXT not executed!\n");
+        vkRes = VK_ERROR_EXTENSION_NOT_PRESENT;
+        goto out;
+    }
+
+    // Next, if so, proceed with the implementation of this function:
+    pIcdSurface =
+        AllocateIcdSurfaceStruct(ptr_instance, sizeof(pIcdSurface->directfb_surf.base), sizeof(pIcdSurface->directfb_surf));
+    if (pIcdSurface == NULL) {
+        vkRes = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
+
+    pIcdSurface->directfb_surf.base.platform = VK_ICD_WSI_PLATFORM_DIRECTFB;
+    pIcdSurface->directfb_surf.dfb = pCreateInfo->dfb;
+    pIcdSurface->directfb_surf.surface = pCreateInfo->surface;
+
+    // Loop through each ICD and determine if they need to create a surface
+    for (struct loader_icd_term *icd_term = ptr_instance->icd_terms; icd_term != NULL; icd_term = icd_term->next, i++) {
+        if (icd_term->scanned_icd->interface_version >= ICD_VER_SUPPORTS_ICD_SURFACE_KHR) {
+            if (NULL != icd_term->dispatch.CreateDirectFBSurfaceEXT) {
+                vkRes = icd_term->dispatch.CreateDirectFBSurfaceEXT(icd_term->instance, pCreateInfo, pAllocator,
+                                                                    &pIcdSurface->real_icd_surfaces[i]);
+                if (VK_SUCCESS != vkRes) {
+                    goto out;
+                }
+            }
+        }
+    }
+
+    *pSurface = (VkSurfaceKHR)pIcdSurface;
+
+out:
+
+    if (VK_SUCCESS != vkRes && NULL != pIcdSurface) {
+        if (NULL != pIcdSurface->real_icd_surfaces) {
+            i = 0;
+            for (struct loader_icd_term *icd_term = ptr_instance->icd_terms; icd_term != NULL; icd_term = icd_term->next, i++) {
+                if ((VkSurfaceKHR)NULL != pIcdSurface->real_icd_surfaces[i] && NULL != icd_term->dispatch.DestroySurfaceKHR) {
+                    icd_term->dispatch.DestroySurfaceKHR(icd_term->instance, pIcdSurface->real_icd_surfaces[i], pAllocator);
+                }
+            }
+            loader_instance_heap_free(ptr_instance, pIcdSurface->real_icd_surfaces);
+        }
+        loader_instance_heap_free(ptr_instance, pIcdSurface);
+    }
+
+    return vkRes;
+}
+
+// This is the trampoline entrypoint for
+// GetPhysicalDeviceDirectFBPresentationSupportEXT
+LOADER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT(VkPhysicalDevice physicalDevice,
+                                                                                               uint32_t queueFamilyIndex,
+                                                                                               IDirectFB *dfb) {
+    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
+    const VkLayerInstanceDispatchTable *disp;
+    disp = loader_get_instance_layer_dispatch(physicalDevice);
+    VkBool32 res = disp->GetPhysicalDeviceDirectFBPresentationSupportEXT(unwrapped_phys_dev, queueFamilyIndex, dfb);
+    return res;
+}
+
+// This is the instance chain terminator function for
+// GetPhysicalDeviceDirectFBPresentationSupportEXT
+VKAPI_ATTR VkBool32 VKAPI_CALL terminator_GetPhysicalDeviceDirectFBPresentationSupportEXT(VkPhysicalDevice physicalDevice,
+                                                                                          uint32_t queueFamilyIndex,
+                                                                                          IDirectFB *dfb) {
+    // First, check to ensure the appropriate extension was enabled:
+    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;
+    struct loader_instance *ptr_instance = (struct loader_instance *)icd_term->this_instance;
+    if (!ptr_instance->wsi_directfb_surface_enabled) {
+        loader_log(
+            ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+            "VK_EXT_directfb_surface extension not enabled.  vkGetPhysicalDeviceWaylandPresentationSupportKHR not executed!\n");
+        return VK_SUCCESS;
+    }
+
+    if (NULL == icd_term->dispatch.GetPhysicalDeviceDirectFBPresentationSupportEXT) {
+        loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+                   "ICD for selected physical device is not exporting vkGetPhysicalDeviceDirectFBPresentationSupportEXT!\n");
+        assert(false && "loader: null GetPhysicalDeviceDirectFBPresentationSupportEXT ICD pointer");
+    }
+
+    return icd_term->dispatch.GetPhysicalDeviceDirectFBPresentationSupportEXT(phys_dev_term->phys_dev, queueFamilyIndex, dfb);
+}
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
+
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
 
 // Functions for the VK_KHR_android_surface extension:
@@ -2183,6 +2313,18 @@
         return true;
     }
 #endif  // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+
+    // Functions for the VK_EXT_directfb_surface extension:
+    if (!strcmp("vkCreateDirectFBSurfaceEXT", name)) {
+        *addr = ptr_instance->wsi_directfb_surface_enabled ? (void *)vkCreateDirectFBSurfaceEXT : NULL;
+        return true;
+    }
+    if (!strcmp("vkGetPhysicalDeviceDirectFBPresentationSupportEXT", name)) {
+        *addr = ptr_instance->wsi_directfb_surface_enabled ? (void *)vkGetPhysicalDeviceDirectFBPresentationSupportEXT : NULL;
+        return true;
+    }
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
 
     // Functions for the VK_KHR_android_surface extension:
diff --git a/loader/wsi.h b/loader/wsi.h
index c7e6eb0..a5a6835 100644
--- a/loader/wsi.h
+++ b/loader/wsi.h
@@ -39,6 +39,9 @@
 #ifdef VK_USE_PLATFORM_XLIB_KHR
         VkIcdSurfaceXlib xlib_surf;
 #endif  // VK_USE_PLATFORM_XLIB_KHR
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+        VkIcdSurfaceDirectFB directfb_surf;
+#endif  // VK_USE_PLATFORM_DIRECTFB_EXT
 #ifdef VK_USE_PLATFORM_MACOS_MVK
         VkIcdSurfaceMacOS macos_surf;
 #endif  // VK_USE_PLATFORM_MACOS_MVK
@@ -124,6 +127,14 @@
                                                                                       uint32_t queueFamilyIndex, Display *dpy,
                                                                                       VisualID visualID);
 #endif
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDirectFBSurfaceEXT(VkInstance instance,
+                                                                   const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo,
+                                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
+VKAPI_ATTR VkBool32 VKAPI_CALL terminator_GetPhysicalDeviceDirectFBPresentationSupportEXT(VkPhysicalDevice physicalDevice,
+                                                                                          uint32_t queueFamilyIndex,
+                                                                                          IDirectFB *dfb);
+#endif
 #ifdef VK_USE_PLATFORM_MACOS_MVK
 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo,
                                                                 const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
diff --git a/scripts/common_codegen.py b/scripts/common_codegen.py
index 11b4fe5..b301b3a 100644
--- a/scripts/common_codegen.py
+++ b/scripts/common_codegen.py
@@ -56,6 +56,7 @@
     'win32' : 'VK_USE_PLATFORM_WIN32_KHR',
     'xcb' : 'VK_USE_PLATFORM_XCB_KHR',
     'xlib' : 'VK_USE_PLATFORM_XLIB_KHR',
+    'directfb' : 'VK_USE_PLATFORM_DIRECTFB_EXT',
     'xlib_xrandr' : 'VK_USE_PLATFORM_XLIB_XRANDR_EXT',
     'provisional' : 'VK_ENABLE_BETA_EXTENSIONS',
 }
diff --git a/scripts/dispatch_table_helper_generator.py b/scripts/dispatch_table_helper_generator.py
index 7aaf17d..57e4c65 100644
--- a/scripts/dispatch_table_helper_generator.py
+++ b/scripts/dispatch_table_helper_generator.py
@@ -37,6 +37,7 @@
                  conventions = None,
                  filename = None,
                  directory = '.',
+                 genpath = None,
                  apiname = None,
                  profile = None,
                  versions = '.*',
@@ -53,9 +54,20 @@
                  apientryp = '',
                  alignFuncParam = 0,
                  expandEnumerants = True):
-        GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        GeneratorOptions.__init__(self,
+                conventions = conventions,
+                filename = filename,
+                directory = directory,
+                genpath = genpath,
+                apiname = apiname,
+                profile = profile,
+                versions = versions,
+                emitversions = emitversions,
+                defaultExtensions = defaultExtensions,
+                addExtensions = addExtensions,
+                removeExtensions = removeExtensions,
+                emitExtensions = emitExtensions,
+                sortProcedure = sortProcedure)
         self.prefixText      = prefixText
         self.genFuncPointers = genFuncPointers
         self.prefixText      = None
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index e5f2e3c..323bee6 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -34,6 +34,7 @@
                  conventions = None,
                  filename = None,
                  directory = '.',
+                 genpath = None,
                  apiname = None,
                  profile = None,
                  versions = '.*',
@@ -54,9 +55,20 @@
                  library_name = '',
                  expandEnumerants = True,
                  helper_file_type = ''):
-        GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        GeneratorOptions.__init__(self,
+                conventions = conventions,
+                filename = filename,
+                directory = directory,
+                genpath = genpath,
+                apiname = apiname,
+                profile = profile,
+                versions = versions,
+                emitversions = emitversions,
+                defaultExtensions = defaultExtensions,
+                addExtensions = addExtensions,
+                removeExtensions = removeExtensions,
+                emitExtensions = emitExtensions,
+                sortProcedure = sortProcedure)
         self.prefixText       = prefixText
         self.genFuncPointers  = genFuncPointers
         self.protectFile      = protectFile
diff --git a/scripts/known_good.json b/scripts/known_good.json
index 542342d..d050a6f 100644
--- a/scripts/known_good.json
+++ b/scripts/known_good.json
@@ -6,7 +6,7 @@
       "sub_dir" : "Vulkan-Headers",
       "build_dir" : "Vulkan-Headers/build",
       "install_dir" : "Vulkan-Headers/build/install",
-      "commit" : "v1.2.135"
+      "commit" : "v1.2.148"
     }
   ],
   "install_names" : {
diff --git a/scripts/loader_extension_generator.py b/scripts/loader_extension_generator.py
index e83cbb4..e64938e 100644
--- a/scripts/loader_extension_generator.py
+++ b/scripts/loader_extension_generator.py
@@ -32,6 +32,7 @@
                  'VK_KHR_xlib_surface',
                  'VK_KHR_xcb_surface',
                  'VK_KHR_wayland_surface',
+                 'VK_EXT_directfb_surface',
                  'VK_KHR_win32_surface',
                  'VK_KHR_android_surface',
                  'VK_MVK_macos_surface',
@@ -101,6 +102,7 @@
                  conventions = None,
                  filename = None,
                  directory = '.',
+                 genpath = None,
                  apiname = None,
                  profile = None,
                  versions = '.*',
@@ -121,9 +123,20 @@
                  indentFuncPointer = False,
                  alignFuncParam = 0,
                  expandEnumerants = True):
-        GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        GeneratorOptions.__init__(self,
+                conventions = conventions,
+                filename = filename,
+                directory = directory,
+                genpath = genpath,
+                apiname = apiname,
+                profile = profile,
+                versions = versions,
+                emitversions = emitversions,
+                defaultExtensions = defaultExtensions,
+                addExtensions = addExtensions,
+                removeExtensions = removeExtensions,
+                emitExtensions = emitExtensions,
+                sortProcedure = sortProcedure)
         self.prefixText      = prefixText
         self.prefixText      = None
         self.apicall         = apicall
diff --git a/scripts/loader_genvk.py b/scripts/loader_genvk.py
index 50e7a2c..7c81858 100644
--- a/scripts/loader_genvk.py
+++ b/scripts/loader_genvk.py
@@ -68,6 +68,9 @@
     # Output target directory
     directory = args.directory
 
+    # Path to generated files, particularly api.py
+    genpath = args.genpath
+
     # Descriptive names for various regexp patterns used to select
     # versions and extensions
     allFeatures     = allExtensions = '.*'
@@ -122,6 +125,7 @@
             conventions       = conventions,
             filename          = 'vk_dispatch_table_helper.h',
             directory         = directory,
+            genpath           = None,
             apiname           = 'vulkan',
             profile           = None,
             versions          = featuresPat,
@@ -145,6 +149,7 @@
             conventions       = conventions,
             filename          = 'vk_layer_dispatch_table.h',
             directory         = directory,
+            genpath           = None,
             apiname           = 'vulkan',
             profile           = None,
             versions          = featuresPat,
@@ -168,6 +173,7 @@
             conventions       = conventions,
             filename          = 'vk_loader_extensions.h',
             directory         = directory,
+            genpath           = None,
             apiname           = 'vulkan',
             profile           = None,
             versions          = featuresPat,
@@ -191,6 +197,7 @@
             conventions       = conventions,
             filename          = 'vk_loader_extensions.c',
             directory         = directory,
+            genpath           = None,
             apiname           = 'vulkan',
             profile           = None,
             versions          = featuresPat,
@@ -214,6 +221,7 @@
             conventions       = conventions,
             filename          = 'vk_object_types.h',
             directory         = directory,
+            genpath           = None,
             apiname           = 'vulkan',
             profile           = None,
             versions          = featuresPat,
@@ -231,7 +239,8 @@
             helper_file_type  = 'object_types_header')
         ]
 
-# Generate a target based on the options in the matching genOpts{} object.
+# Create an API generator and corresponding generator options based on
+# the requested target and command line options.
 # This is encapsulated in a function so it can be profiled and/or timed.
 # The args parameter is an parsed argument object containing the following
 # fields that are used:
@@ -243,9 +252,10 @@
 def genTarget(args):
     global genOpts
 
-    # Create generator options with specified parameters
+    # Create generator options with parameters specified on command line
     makeGenOpts(args)
 
+    # Select a generator matching the requested target
     if (args.target in genOpts.keys()):
         createGenerator = genOpts[args.target][0]
         options = genOpts[args.target][1]
@@ -259,19 +269,15 @@
             write('* options.removeExtensions  =', options.removeExtensions, file=sys.stderr)
             write('* options.emitExtensions    =', options.emitExtensions, file=sys.stderr)
 
-        startTimer(args.time)
         gen = createGenerator(errFile=errWarn,
                               warnFile=errWarn,
                               diagFile=diag)
-        reg.setGenerator(gen)
-        reg.apiGen(options)
-
         if not args.quiet:
             write('* Generated', options.filename, file=sys.stderr)
-        endTimer(args.time, '* Time to generate ' + options.filename + ' =')
+        return (gen, options)
     else:
-        write('No generator options for unknown target:',
-              args.target, file=sys.stderr)
+        write('No generator options for unknown target:', args.target, file=sys.stderr)
+        return none
 
 # -feature name
 # -extension name
@@ -315,7 +321,9 @@
     parser.add_argument('-time', action='store_true',
                         help='Enable timing')
     parser.add_argument('-validate', action='store_true',
-                        help='Enable group validation')
+                        help='Enable XML group validation')
+    parser.add_argument('-genpath', action='store', default='gen',
+                        help='Path to generated files')
     parser.add_argument('-o', action='store', dest='directory',
                         default='.',
                         help='Create target and related files in specified directory')
@@ -357,19 +365,33 @@
     args.feature = [name for arg in args.feature for name in arg.split()]
     args.extension = [name for arg in args.extension for name in arg.split()]
 
-    # Load & parse registry
-    reg = Registry()
+    # create error/warning & diagnostic files
+    if args.errfile:
+        errWarn = open(args.errfile, 'w', encoding='utf-8')
+    else:
+        errWarn = sys.stderr
 
+    if args.diagfile:
+        diag = open(args.diagfile, 'w', encoding='utf-8')
+    else:
+        diag = None
+
+    # Create the API generator & generator options
+    (gen, options) = genTarget(args)
+
+    # Create the registry object with the specified generator and generator
+    # options. The options are set before XML loading as they may affect it.
+    reg = Registry(gen, options)
+
+    # Parse the specified registry XML into an ElementTree objec
     startTimer(args.time)
     tree = etree.parse(args.registry)
     endTimer(args.time, '* Time to make ElementTree =')
 
-    if args.debug:
-        pdb.run('reg.loadElementTree(tree)')
-    else:
-        startTimer(args.time)
-        reg.loadElementTree(tree)
-        endTimer(args.time, '* Time to parse ElementTree =')
+    # Load the XML tree into the registry object
+    startTimer(args.time)
+    reg.loadElementTree(tree)
+    endTimer(args.time, '* Time to parse ElementTree =')
 
     if (args.validate):
         reg.validateGroups()
@@ -378,23 +400,13 @@
         write('* Dumping registry to regdump.txt', file=sys.stderr)
         reg.dumpReg(filehandle = open('regdump.txt', 'w', encoding='utf-8'))
 
-    # create error/warning & diagnostic files
-    if (args.errfile):
-        errWarn = open(args.errfile, 'w', encoding='utf-8')
-    else:
-        errWarn = sys.stderr
-
-    if (args.diagfile):
-        diag = open(args.diagfile, 'w', encoding='utf-8')
-    else:
-        diag = None
-
+    # Finally, use the output generator to create the requested targe
     if (args.debug):
-        pdb.run('genTarget(args)')
-    elif (args.profile):
-        import cProfile, pstats
-        cProfile.run('genTarget(args)', 'profile.txt')
-        p = pstats.Stats('profile.txt')
-        p.strip_dirs().sort_stats('time').print_stats(50)
+        pdb.run('reg.apiGen()')
     else:
-        genTarget(args)
+        startTimer(args.time)
+        reg.apiGen()
+        endTimer(args.time, '* Time to generate ' + options.filename + ' =')
+
+    if not args.quiet:
+        write('* Generated', options.filename, file=sys.stderr)
diff --git a/scripts/update_deps.py b/scripts/update_deps.py
index f1fe36d..ea21c9f 100755
--- a/scripts/update_deps.py
+++ b/scripts/update_deps.py
@@ -2,7 +2,7 @@
 
 # Copyright 2017 The Glslang Authors. All rights reserved.
 # Copyright (c) 2018 Valve Corporation
-# Copyright (c) 2018 LunarG, Inc.
+# Copyright (c) 2018-2020 LunarG, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -250,6 +250,8 @@
 import multiprocessing
 import shlex
 import shutil
+import stat
+import time
 
 KNOWN_GOOD_FILE_NAME = 'known_good.json'
 
@@ -265,6 +267,14 @@
 DEVNULL = open(os.devnull, 'wb')
 
 
+def on_rm_error( func, path, exc_info):
+    """Error handler for recursively removing a directory. The
+    shutil.rmtree function can fail on Windows due to read-only files.
+    This handler will change the permissions for tha file and continue.
+    """
+    os.chmod( path, stat.S_IWRITE )
+    os.unlink( path )
+
 def command_output(cmd, directory, fail_ok=False):
     """Runs a command in a directory and returns its standard output stream.
 
@@ -333,17 +343,52 @@
         if self.build_platforms == [] or platform.system().lower() in self.build_platforms:
             self.on_build_platform = True
 
-    def Clone(self):
-        distutils.dir_util.mkpath(self.repo_dir)
-        command_output(['git', 'clone', self.url, '.'], self.repo_dir)
+    def Clone(self, retries=10, retry_seconds=60):
+        print('Cloning {n} into {d}'.format(n=self.name, d=self.repo_dir))
+        for retry in range(retries):
+            distutils.dir_util.mkpath(self.repo_dir)
+            try:
+                command_output(['git', 'clone', self.url, '.'], self.repo_dir)
+                # If we get here, we didn't raise an error
+                return
+            except RuntimeError as e:
+                print("Error cloning on iteration {}/{}: {}".format(retry + 1, retries, e))
+                if retry + 1 < retries:
+                    if retry_seconds > 0:
+                        print("Waiting {} seconds before trying again".format(retry_seconds))
+                        time.sleep(retry_seconds)
+                    if os.path.isdir(self.repo_dir):
+                        print("Removing old tree {}".format(self.repo_dir))
+                        shutil.rmtree(self.repo_dir, onerror=on_rm_error)
+                    continue
 
-    def Fetch(self):
-        command_output(['git', 'fetch', 'origin'], self.repo_dir)
+                # If we get here, we've exhausted our retries.
+                print("Failed to clone {} on all retries.".format(self.url))
+                raise e
+
+    def Fetch(self, retries=10, retry_seconds=60):
+        for retry in range(retries):
+            try:
+                command_output(['git', 'fetch', 'origin'], self.repo_dir)
+                # if we get here, we didn't raise an error, and we're done
+                return
+            except RuntimeError as e:
+                print("Error fetching on iteration {}/{}: {}".format(retry + 1, retries, e))
+                if retry + 1 < retries:
+                    if retry_seconds > 0:
+                        print("Waiting {} seconds before trying again".format(retry_seconds))
+                        time.sleep(retry_seconds)
+                    continue
+
+                # If we get here, we've exhausted our retries.
+                print("Failed to fetch {} on all retries.".format(self.url))
+                raise e
 
     def Checkout(self):
         print('Checking out {n} in {d}'.format(n=self.name, d=self.repo_dir))
         if self._args.do_clean_repo:
-            shutil.rmtree(self.repo_dir, ignore_errors=True)
+            if os.path.isdir(self.repo_dir):
+                shutil.rmtree(self.repo_dir, onerror = on_rm_error)
         if not os.path.exists(os.path.join(self.repo_dir, '.git')):
             self.Clone()
         self.Fetch()
@@ -394,7 +439,7 @@
         # repo's install dir.
         for d in self.deps:
             dep_commit = [r for r in repos if r.name == d['repo_name']]
-            if len(dep_commit):
+            if len(dep_commit) and dep_commit[0].on_build_platform:
                 cmake_cmd.append('-D{var_name}={install_dir}'.format(
                     var_name=d['var_name'],
                     install_dir=dep_commit[0].install_dir))
@@ -411,9 +456,12 @@
         # Use the CMake -A option to select the platform architecture
         # without needing a Visual Studio generator.
         if platform.system() == 'Windows':
-            if self._args.arch == '64' or self._args.arch == 'x64' or self._args.arch == 'win64':
+            if self._args.arch.lower() == '64' or self._args.arch == 'x64' or self._args.arch == 'win64':
                 cmake_cmd.append('-A')
                 cmake_cmd.append('x64')
+            else:
+                cmake_cmd.append('-A')
+                cmake_cmd.append('Win32')
 
         # Apply a generator, if one is specified.  This can be used to supply
         # a specific generator for the dependent repositories to match
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d9418e5..8b38ef3 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -116,8 +116,8 @@
                             GTEST_COPY_SRC2)
         file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG> GTEST_COPY_DEST)
     else()
-        file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googeltest/gtest_main.dll GTEST_COPY_SRC1)
-        file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googletest/gtest.dll GTEST_COPY_SRC2)
+        file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googletest/gtest_main$<$<CONFIG:Debug>:d>.dll GTEST_COPY_SRC1)
+        file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googletest/gtest$<$<CONFIG:Debug>:d>.dll GTEST_COPY_SRC2)
         file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR} GTEST_COPY_DEST)
     endif()
     add_custom_command(TARGET vk_loader_validation_tests POST_BUILD
diff --git a/tests/run_loader_tests.sh b/tests/run_loader_tests.sh
index 329d17b..23f2817 100755
--- a/tests/run_loader_tests.sh
+++ b/tests/run_loader_tests.sh
@@ -45,9 +45,9 @@
        echo "Environment Variable Path test FAILED - Implicit layer path incorrect" >&2
        exit 1
     fi
-    # Sadly, the loader does not clean up this path and just stumbles through it.
-    # So just make sure it is the same.
-    right_path="${vk_layer_path}"
+    # The loader cleans up this path to remove the empty paths, so we need to clean up the right path, too
+    right_path="${vk_layer_path//:::::/:}"
+    right_path="${right_path//::::/:}"
     echo "$output" | grep -q "$right_path"
     ec=$?
     if [ $ec -eq 1 ]