Snap for 5430508 from 932fa4323a1a4147fc0df55f120dbce86554ab2c to qt-release

Change-Id: Ib6da6f9b0f2ee86e5c4058754fb7d0449276b4b4
diff --git a/.travis.yml b/.travis.yml
index 07e3b76..5013051 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
 # Build Configuration for Travis CI
 # https://travis-ci.org
 
-dist: trusty
+dist: xenial
 sudo: required
 language: cpp
 
@@ -14,11 +14,11 @@
     # Android build.
     - os: linux
       compiler: gcc
-      env: VULKAN_BUILD_TARGET=ANDROID ANDROID_TARGET=android-23 ANDROID_ABI=armeabi-v7a
+      env: VULKAN_BUILD_TARGET=ANDROID ANDROID_TARGET=android-26 ANDROID_ABI=armeabi-v7a
     # Android 64-bit build.
     - os: linux
       compiler: gcc
-      env: VULKAN_BUILD_TARGET=ANDROID ANDROID_TARGET=android-23 ANDROID_ABI=arm64-v8a
+      env: VULKAN_BUILD_TARGET=ANDROID ANDROID_TARGET=android-26 ANDROID_ABI=arm64-v8a
     # Linux GCC debug build.
     - os: linux
       compiler: gcc
@@ -46,15 +46,16 @@
       # Install the appropriate Linux packages.
       sudo apt-get -qq update
       sudo apt-get -y install libxkbcommon-dev libwayland-dev libmirclient-dev libxrandr-dev \
-                              libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-ewmh-dev
+                              libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-ewmh-dev \
+                              libxcb-randr0-dev
     fi
   - |
     if [[ "$VULKAN_BUILD_TARGET" == "ANDROID" ]]; then
       # Install the Android NDK.
       export ARCH=`uname -m`
-      wget http://dl.google.com/android/repository/android-ndk-r15c-linux-${ARCH}.zip
-      unzip -u -q android-ndk-r15c-linux-${ARCH}.zip
-      export ANDROID_NDK_HOME=`pwd`/android-ndk-r15c
+      wget http://dl.google.com/android/repository/android-ndk-r18b-linux-${ARCH}.zip
+      unzip -u -q android-ndk-r18b-linux-${ARCH}.zip
+      export ANDROID_NDK_HOME=`pwd`/android-ndk-r18b
       export JAVA_HOME="/usr/lib/jvm/java-8-oracle"
       export PATH="$ANDROID_NDK_HOME:$PATH"
     fi
diff --git a/BUILD.md b/BUILD.md
index 821d9bc..b351433 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -347,7 +347,7 @@
 After making any changes to the repository, you should perform some quick
 sanity tests, including the run_all_tests Powershell script. In addition,
 running sample applications such as the
-[cube demo](https://www.github.com/KhronosGroup/Vulkan-Tools.git)
+[vkcube demo](https://www.github.com/KhronosGroup/Vulkan-Tools.git)
 with validation enabled is advised.
 
 To run the validation test script, open a Powershell Console, change to the
@@ -575,7 +575,7 @@
 
     export VK_LAYER_PATH=<path to your repository root>/build/layers
 
-You can run the `cube` or `vulkaninfo` applications from the Vulkan-Tools
+You can run the `vkcube` or `vulkaninfo` applications from the Vulkan-Tools
 repository to see which driver, loader and layers are being used.
 
 ## Building On Android
@@ -690,8 +690,8 @@
 ### Android Tests and Demos
 
 After making any changes to the repository you should perform some quick
-sanity tests, including the layer validation tests and the cube and smoke
-demos with validation enabled.
+sanity tests, including the layer validation tests and the vkcube
+demo with validation enabled.
 
 #### Run Layer Validation Tests
 
@@ -820,7 +820,7 @@
 
 - `vk_layer_validation_tests`: Test Vulkan validation layers
 
-Further testing and sanity checking can be achieved by running the cube and
+Further testing and sanity checking can be achieved by running the vkcube and
 vulkaninfo applications in the
 [Vulkan-Tools](https://github.com/KhronosGroup/Vulkan-Tools)
 repository.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0965a73..61a266c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 # ~~~
-# Copyright (c) 2014-2018 Valve Corporation
-# Copyright (c) 2014-2018 LunarG, Inc.
+# Copyright (c) 2014-2019 Valve Corporation
+# Copyright (c) 2014-2019 LunarG, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -38,7 +38,18 @@
 
 find_package(PythonInterp 3 REQUIRED)
 
-find_package(VulkanHeaders)
+if (TARGET Vulkan::Headers)
+    message(STATUS "Using Vulkan headers from Vulkan::Headers target")
+    get_target_property(VulkanHeaders_INCLUDE_DIRS Vulkan::Headers INTERFACE_INCLUDE_DIRECTORIES)
+    get_target_property(VulkanRegistry_DIR Vulkan::Registry INTERFACE_INCLUDE_DIRECTORIES)
+else()
+    find_package(VulkanHeaders REQUIRED)
+
+    # xxxnsubtil: this should eventually be replaced by exported targets
+    add_library(Vulkan-Headers INTERFACE)
+    target_include_directories(Vulkan-Headers INTERFACE ${VulkanHeaders_INCLUDE_DIRS})
+    add_library(Vulkan::Headers ALIAS Vulkan-Headers)
+endif()
 
 option(USE_CCACHE "Use ccache" OFF)
 if(USE_CCACHE)
@@ -100,6 +111,13 @@
                         -fno-strict-aliasing
                         -fno-builtin-memcmp
                         -fvisibility=hidden)
+
+    # Treat warnings as errors for versions of GCC and Clang that are shipped on Ubuntu 18.04 or older.
+    if((CMAKE_COMPILER_IS_GNUCXX AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.3.0)) OR
+       (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.8.0)))
+        add_compile_options(-Werror)
+    endif()
+
     set(CMAKE_C_STANDARD 99)
     set(CMAKE_CXX_STANDARD 11)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
@@ -125,7 +143,7 @@
     add_compile_options("/w34245")
 endif()
 
-if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
+if(TARGET gtest OR IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/external/googletest)
     option(BUILD_TESTS "Build tests" ON)
 else()
     option(BUILD_TESTS "Build tests" OFF)
@@ -135,119 +153,138 @@
 option(BUILD_LAYERS "Build layers" ON)
 option(BUILD_LAYER_SUPPORT_FILES "Generate layer files" OFF) # For generating files when not building layers
 
-set(GLSLANG_INSTALL_DIR "GLSLANG-NOTFOUND" CACHE PATH "Absolute path to a glslang install directory")
-if(NOT GLSLANG_INSTALL_DIR AND NOT DEFINED ENV{GLSLANG_INSTALL_DIR})
-    message(FATAL_ERROR "Must define location of glslang binaries -- see BUILD.md")
-endif()
+if(BUILD_TESTS OR BUILD_LAYERS)
 
-# CMake command line option overrides environment variable
-if(NOT GLSLANG_INSTALL_DIR)
-    set(GLSLANG_INSTALL_DIR $ENV{GLSLANG_INSTALL_DIR})
-endif()
-message(STATUS "Using glslang install located at ${GLSLANG_INSTALL_DIR}")
-set(SPIRV_TOOLS_BINARY_ROOT "${GLSLANG_INSTALL_DIR}/lib"
-    CACHE PATH "User defined path to the SPIRV-Tools binaries for this project")
-set(SPIRV_TOOLS_OPT_BINARY_ROOT "${GLSLANG_INSTALL_DIR}/lib"
-    CACHE PATH "User defined path to the SPIRV-Tools-opt binaries for this project")
-set(GLSLANG_SPIRV_INCLUDE_DIR "${GLSLANG_INSTALL_DIR}/include" CACHE PATH "Path to glslang spirv headers")
-set(SPIRV_TOOLS_INCLUDE_DIR "${GLSLANG_INSTALL_DIR}/include" CACHE PATH "Path to spirv tools headers")
-set(GLSLANG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
-set(GLSLANG_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
-set(SPIRV_TOOLS_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
-set(SPIRV_TOOLS_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
-set(SPIRV_TOOLS_OPT_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
-set(SPIRV_TOOLS_OPT_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+    set(GLSLANG_INSTALL_DIR "GLSLANG-NOTFOUND" CACHE PATH "Absolute path to a glslang install directory")
+    if(NOT GLSLANG_INSTALL_DIR AND NOT DEFINED ENV{GLSLANG_INSTALL_DIR} AND NOT TARGET glslang)
+        message(FATAL_ERROR "Must define location of glslang binaries -- see BUILD.md")
+    endif()
 
-find_library(GLSLANG_LIB NAMES glslang HINTS ${GLSLANG_SEARCH_PATH})
+    # GLSLANG_INSTALL_DIR is used as the path to all dependent projects' install dirs
+    # CMake command line option overrides environment variable
+    if(NOT GLSLANG_INSTALL_DIR)
+        set(GLSLANG_INSTALL_DIR $ENV{GLSLANG_INSTALL_DIR})
+    endif()
 
-find_library(OGLCompiler_LIB NAMES OGLCompiler HINTS ${GLSLANG_SEARCH_PATH})
+    if (NOT TARGET glslang)
+        message(STATUS "Using glslang install located at ${GLSLANG_INSTALL_DIR}")
+        set(GLSLANG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+        set(GLSLANG_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+        set(GLSLANG_SPIRV_INCLUDE_DIR "${GLSLANG_INSTALL_DIR}/include" CACHE PATH "Path to glslang spirv headers")
 
-find_library(OSDependent_LIB NAMES OSDependent HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(GLSLANG_LIB NAMES glslang HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(OGLCompiler_LIB NAMES OGLCompiler HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(OSDependent_LIB NAMES OSDependent HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(HLSL_LIB NAMES HLSL HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(SPIRV_LIB NAMES SPIRV HINTS ${GLSLANG_SEARCH_PATH})
+        find_library(SPIRV_REMAPPER_LIB NAMES SPVRemapper HINTS ${GLSLANG_SEARCH_PATH})
 
-find_library(HLSL_LIB NAMES HLSL HINTS ${GLSLANG_SEARCH_PATH})
+        if(WIN32)
+            add_library(glslang STATIC IMPORTED)
+            add_library(OGLCompiler STATIC IMPORTED)
+            add_library(OSDependent STATIC IMPORTED)
+            add_library(HLSL STATIC IMPORTED)
+            add_library(SPIRV STATIC IMPORTED)
+            add_library(SPVRemapper STATIC IMPORTED)
+            add_library(Loader STATIC IMPORTED)
 
-find_library(SPIRV_LIB NAMES SPIRV HINTS ${GLSLANG_SEARCH_PATH})
+            find_library(GLSLANG_DLIB NAMES glslangd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
+            find_library(OGLCompiler_DLIB NAMES OGLCompilerd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
+            find_library(OSDependent_DLIB NAMES OSDependentd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
+            find_library(HLSL_DLIB NAMES HLSLd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
+            find_library(SPIRV_DLIB NAMES SPIRVd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
+            find_library(SPIRV_REMAPPER_DLIB NAMES SPVRemapperd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
 
-find_library(SPIRV_REMAPPER_LIB NAMES SPVRemapper HINTS ${GLSLANG_SEARCH_PATH})
+            set_target_properties(glslang
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${GLSLANG_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${GLSLANG_DLIB}")
+            set_target_properties(OGLCompiler
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${OGLCompiler_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${OGLCompiler_DLIB}")
+            set_target_properties(OSDependent
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${OSDependent_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${OSDependent_DLIB}")
+            set_target_properties(HLSL
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${HLSL_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${HLSL_DLIB}")
+            set_target_properties(SPIRV
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${SPIRV_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${SPIRV_DLIB}")
+            set_target_properties(SPVRemapper
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${SPIRV_REMAPPER_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${SPIRV_REMAPPER_DLIB}")
 
-find_library(SPIRV_TOOLS_LIB NAMES SPIRV-Tools HINTS ${SPIRV_TOOLS_SEARCH_PATH})
+            set(GLSLANG_LIBRARIES glslang OGLCompiler OSDependent HLSL SPIRV SPVRemapper ${SPIRV_TOOLS_LIBRARIES})
+        else()
+            set(GLSLANG_LIBRARIES
+                ${GLSLANG_LIB}
+                ${OGLCompiler_LIB}
+                ${OSDependent_LIB}
+                ${HLSL_LIB}
+                ${SPIRV_LIB}
+                ${SPIRV_REMAPPER_LIB}
+                ${SPIRV_TOOLS_LIBRARIES})
+        endif()
+    else()
+        set(GLSLANG_SPIRV_INCLUDE_DIR "${glslang_SOURCE_DIR}" CACHE PATH "Path to glslang spirv headers")
+        set(GLSLANG_LIBRARIES glslang SPIRV SPVRemapper)
+    endif()
 
-find_library(SPIRV_TOOLS_OPT_LIB NAMES SPIRV-Tools-opt HINTS ${SPIRV_TOOLS_OPT_SEARCH_PATH})
+    # spirv-tools
+    if (NOT TARGET SPIRV-Tools)
+        set(SPIRV_TOOLS_BINARY_ROOT "${GLSLANG_INSTALL_DIR}/lib"
+            CACHE PATH "User defined path to the SPIRV-Tools binaries for this project")
+        set(SPIRV_TOOLS_OPT_BINARY_ROOT "${GLSLANG_INSTALL_DIR}/lib"
+            CACHE PATH "User defined path to the SPIRV-Tools-opt binaries for this project")
+        set(SPIRV_TOOLS_INCLUDE_DIR "${GLSLANG_INSTALL_DIR}/include" CACHE PATH "Path to spirv tools headers")
+        set(SPIRV_TOOLS_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+        set(SPIRV_TOOLS_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+        set(SPIRV_TOOLS_OPT_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
+        set(SPIRV_TOOLS_OPT_DEBUG_SEARCH_PATH "${GLSLANG_INSTALL_DIR}/lib")
 
-if(WIN32)
-    add_library(glslang STATIC IMPORTED)
-    add_library(OGLCompiler STATIC IMPORTED)
-    add_library(OSDependent STATIC IMPORTED)
-    add_library(HLSL STATIC IMPORTED)
-    add_library(SPIRV STATIC IMPORTED)
-    add_library(SPVRemapper STATIC IMPORTED)
-    add_library(Loader STATIC IMPORTED)
-    add_library(SPIRV-Tools-opt STATIC IMPORTED)
-    add_library(SPIRV-Tools STATIC IMPORTED)
+        find_library(SPIRV_TOOLS_LIB NAMES SPIRV-Tools HINTS ${SPIRV_TOOLS_SEARCH_PATH})
+        find_library(SPIRV_TOOLS_OPT_LIB NAMES SPIRV-Tools-opt HINTS ${SPIRV_TOOLS_OPT_SEARCH_PATH})
 
-    find_library(GLSLANG_DLIB NAMES glslangd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(OGLCompiler_DLIB NAMES OGLCompilerd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(OSDependent_DLIB NAMES OSDependentd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(HLSL_DLIB NAMES HLSLd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(SPIRV_DLIB NAMES SPIRVd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(SPIRV_REMAPPER_DLIB NAMES SPVRemapperd HINTS ${GLSLANG_DEBUG_SEARCH_PATH})
-    find_library(SPIRV_TOOLS_DLIB NAMES SPIRV-Toolsd HINTS ${SPIRV_TOOLS_DEBUG_SEARCH_PATH})
-    find_library(SPIRV_TOOLS_OPT_DLIB NAMES SPIRV-Tools-optd HINTS ${SPIRV_TOOLS_OPT_DEBUG_SEARCH_PATH})
-    set_target_properties(glslang
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${GLSLANG_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${GLSLANG_DLIB}")
-    set_target_properties(OGLCompiler
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${OGLCompiler_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${OGLCompiler_DLIB}")
-    set_target_properties(OSDependent
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${OSDependent_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${OSDependent_DLIB}")
-    set_target_properties(HLSL
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${HLSL_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${HLSL_DLIB}")
-    set_target_properties(SPIRV
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${SPIRV_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${SPIRV_DLIB}")
-    set_target_properties(SPVRemapper
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${SPIRV_REMAPPER_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${SPIRV_REMAPPER_DLIB}")
-    set_target_properties(SPIRV-Tools
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${SPIRV_TOOLS_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${SPIRV_TOOLS_DLIB}")
-    set_target_properties(SPIRV-Tools-opt
-                          PROPERTIES IMPORTED_LOCATION
-                                     "${SPIRV_TOOLS_OPT_LIB}"
-                                     IMPORTED_LOCATION_DEBUG
-                                     "${SPIRV_TOOLS_OPT_DLIB}")
-endif()
+        if(WIN32)
+            add_library(SPIRV-Tools-opt STATIC IMPORTED)
+            add_library(SPIRV-Tools STATIC IMPORTED)
 
-if(WIN32)
-    set(SPIRV_TOOLS_LIBRARIES SPIRV-Tools-opt SPIRV-Tools)
-    set(GLSLANG_LIBRARIES glslang OGLCompiler OSDependent HLSL SPIRV SPVRemapper ${SPIRV_TOOLS_LIBRARIES})
-else()
-    set(SPIRV_TOOLS_LIBRARIES ${SPIRV_TOOLS_OPT_LIB} ${SPIRV_TOOLS_LIB})
-    set(GLSLANG_LIBRARIES
-        ${GLSLANG_LIB}
-        ${OGLCompiler_LIB}
-        ${OSDependent_LIB}
-        ${HLSL_LIB}
-        ${SPIRV_LIB}
-        ${SPIRV_REMAPPER_LIB}
-        ${SPIRV_TOOLS_LIBRARIES})
+            find_library(SPIRV_TOOLS_DLIB NAMES SPIRV-Toolsd HINTS ${SPIRV_TOOLS_DEBUG_SEARCH_PATH})
+            find_library(SPIRV_TOOLS_OPT_DLIB NAMES SPIRV-Tools-optd HINTS ${SPIRV_TOOLS_OPT_DEBUG_SEARCH_PATH})
+
+            set_target_properties(SPIRV-Tools
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${SPIRV_TOOLS_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${SPIRV_TOOLS_DLIB}")
+            set_target_properties(SPIRV-Tools-opt
+                                  PROPERTIES IMPORTED_LOCATION
+                                             "${SPIRV_TOOLS_OPT_LIB}"
+                                             IMPORTED_LOCATION_DEBUG
+                                             "${SPIRV_TOOLS_OPT_DLIB}")
+
+            set(SPIRV_TOOLS_LIBRARIES SPIRV-Tools-opt SPIRV-Tools)
+        else()
+            set(SPIRV_TOOLS_LIBRARIES ${SPIRV_TOOLS_OPT_LIB} ${SPIRV_TOOLS_LIB})
+        endif()
+    else()
+        set(SPIRV_TOOLS_LIBRARIES SPIRV-Tools SPIRV-Tools-opt)
+        set(SPIRV_TOOLS_INCLUDE_DIR "${spirv-tools_SOURCE_DIR}/include" CACHE PATH "Path to spirv tools headers")
+    endif()
+
+    set(GLSLANG_LIBRARIES ${GLSLANG_LIBRARIES} ${SPIRV_TOOLS_LIBRARIES})
 endif()
 
 # Generate dependent helper files ------------------------------------------------------------------------------------------------
@@ -267,7 +304,7 @@
 endmacro()
 
 # Add rules to generate XML-derived source files.
-GenerateFromVkXml(loader_extension_generator.py vk_layer_dispatch_table.h)
+GenerateFromVkXml(layer_dispatch_table_generator.py vk_layer_dispatch_table.h)
 GenerateFromVkXml(dispatch_table_helper_generator.py vk_dispatch_table_helper.h)
 GenerateFromVkXml(helper_file_generator.py vk_safe_struct.h)
 GenerateFromVkXml(helper_file_generator.py vk_safe_struct.cpp)
@@ -277,7 +314,7 @@
 GenerateFromVkXml(helper_file_generator.py vk_typemap_helper.h)
 
 # This target causes the source files to be generated.
-add_custom_target(generate_helper_files
+add_custom_target(VulkanVL_generate_helper_files
                   DEPENDS vk_enum_string_helper.h
                           vk_safe_struct.h
                           vk_safe_struct.cpp
@@ -286,7 +323,7 @@
                           vk_dispatch_table_helper.h
                           vk_extension_helper.h
                           vk_typemap_helper.h)
-set_target_properties(generate_helper_files PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
+set_target_properties(VulkanVL_generate_helper_files PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
 
 # VkLayer_utils library ----------------------------------------------------------------------------------------------------------
 # For Windows, we use a static lib because the Windows loader has a fairly restrictive loader search path that can't be easily
@@ -299,12 +336,13 @@
             layers/vk_layer_extension_utils.cpp
             layers/vk_layer_utils.cpp
             layers/vk_format_utils.cpp)
+target_link_libraries(VkLayer_utils PUBLIC Vulkan::Headers)
 if(WIN32)
     target_compile_definitions(VkLayer_utils PUBLIC _CRT_SECURE_NO_WARNINGS)
 endif()
 install(TARGETS VkLayer_utils DESTINATION ${CMAKE_INSTALL_LIBDIR})
 set_target_properties(VkLayer_utils PROPERTIES LINKER_LANGUAGE CXX)
-add_dependencies(VkLayer_utils generate_helper_files)
+add_dependencies(VkLayer_utils VulkanVL_generate_helper_files)
 target_include_directories(VkLayer_utils
                            PUBLIC ${VulkanHeaders_INCLUDE_DIR}
                                   ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 24d8ed3..ba8a016 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -34,8 +34,9 @@
 * _Incomplete_:   These issues refer to missing validation checks that users have encountered during application
 development that would have been directly useful, and are high priority.
 * _Enhancement_:  These issues refer to ideas for extending or improving the validation layers.
+* _Triaged_:      These issues have been assessed and/or reviewed
 
-It is the maintainers goal for all issues to be assigned within one business day of their submission. If you choose
+It is the maintainers goal for all issues to be assigned or triaged within one business day of their submission. If you choose
 to work on an issue that is assigned, simply coordinate with the current assignee.
 
 ### **How to Submit Fixes**
@@ -47,6 +48,9 @@
   creating a branch with your commits, and then [submitting a pull request](https://help.github.com/articles/using-pull-requests/).
 * Please read and adhere to the style and process [guidelines ](#coding-conventions-and-formatting) enumerated below.
 * Please base your fixes on the master branch.  SDK branches are generally not updated except for critical fixes needed to repair an SDK release.
+* The resulting Pull Request will be assigned to a repository maintainer. It is the maintainer's responsibility to ensure the Pull Request
+  passes the Google/LunarG internal CI processes. Once the Pull Request has been approved and is passing internal CI, a repository maintainer
+  will merge the PR.
 
 
 #### **Coding Conventions and Formatting**
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
deleted file mode 100644
index 586d82d..0000000
--- a/COPYRIGHT.txt
+++ /dev/null
@@ -1,131 +0,0 @@
-This file contains other licenses and their copyrights that appear in this
-repository besides Apache 2.0 license.
-
-===================================================
-/*
-  Copyright (c) 2009 Dave Gamble
-
-  Permission is hereby granted, free of charge, to any person obtaining a copy
-  of this software and associated documentation files (the "Software"), to deal
-  in the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-*/
-
-===================================================
-/*
-
-    Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
-
-    Permission to use, copy, modify, and distribute this software and its
-    documentation for any purpose is hereby granted without fee, provided
-    that this copyright and permissions notice appear in all copies and
-    derivatives.
-
-    This software is supplied "as is" without express or implied warranty.
-
-    But that said, if there are any problems please get in touch.
-
-*/
-
-===================================================
-Copyright 2008, Google Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-    * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-    * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-===================================================
-Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-
-* Neither the names of Kitware, Inc., the Insight Software Consortium,
-  nor the names of their contributors may be used to endorse or promote
-  products derived from this software without specific prior written
-  permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-===================================================
-Copyright (c) 2011 Fredrik Höglund <fredrik@kde.org>
-Copyright (c) 2008 Helio Chissini de Castro, <helio@kde.org>
-Copyright (c) 2007 Matthias Kretz, <kretz@kde.org>
-
-Redistribution and use is allowed according to the terms of the BSD license.
-
-===================================================
-/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
-/// Permission is hereby granted, free of charge, to any person obtaining a copy
-/// of this software and associated documentation files (the "Software"), to deal
-/// in the Software without restriction, including without limitation the rights
-/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-/// copies of the Software, and to permit persons to whom the Software is
-/// furnished to do so, subject to the following conditions:
-/// 
-/// The above copyright notice and this permission notice shall be included in
-/// all copies or substantial portions of the Software.
-///
-/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-/// THE SOFTWARE.
-///
diff --git a/LICENSE.txt b/LICENSE.txt
index d645695..6599e31 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,3 +1,8 @@
+The majority of files in this project use the Apache 2.0 License.
+There are a few exceptions and their license can be found in the source.
+Any license deviations from Apache 2.0 are "more permissive" licenses.
+
+===========================================================================================
 
                                  Apache License
                            Version 2.0, January 2004
diff --git a/README.md b/README.md
index a5dca0c..b5a6cdc 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,14 @@
 Information on how to enable the various Validation layers is in
 [layers/README.md](layers/README.md).
 
+## Version Tagging Scheme
+
+Updates to the `Vulkan-ValidationLayers` repository which correspond to a new Vulkan specification release are tagged using the following format: `v<`_`version`_`>` (e.g., `v1.1.96`).
+
+**Note**: Marked version releases have undergone thorough testing but do not imply the same quality level as SDK tags. SDK tags follow the `sdk-<`_`version`_`>.<`_`patch`_`>` format (e.g., `sdk-1.1.92.0`).
+
+This scheme was adopted following the 1.1.96 Vulkan specification release.
+
 ## License
 This work is released as open source under a Apache-style license from Khronos including a Khronos copyright.
 
diff --git a/build-android/AndroidManifest.xml b/build-android/AndroidManifest.xml
index 0f0a5ff..d057d6c 100644
--- a/build-android/AndroidManifest.xml
+++ b/build-android/AndroidManifest.xml
@@ -2,7 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.VulkanLayerValidationTests" android:versionCode="1" android:versionName="1.0">
 
     <!-- This is the platform API where NativeActivity was introduced. -->
-    <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23"/>
+    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26"/>
 
     <!-- This .apk has no Java code itself, so set hasCode to false. -->
     <application android:label="@string/app_name" android:hasCode="false" android:debuggable='false'>
diff --git a/build-android/android-generate.bat b/build-android/android-generate.bat
index 99bfcbb..106dd45 100644
--- a/build-android/android-generate.bat
+++ b/build-android/android-generate.bat
@@ -27,14 +27,21 @@
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_enum_string_helper.h
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_object_types.h
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_dispatch_table_helper.h
-py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% thread_check.h
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% thread_safety.cpp
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% thread_safety.h
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% parameter_validation.cpp
-py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% unique_objects_wrappers.h
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% parameter_validation.h
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_layer_dispatch_table.h
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_extension_helper.h
-py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% object_tracker.cpp
 py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% vk_typemap_helper.h
 
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% object_tracker.cpp
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% object_tracker.h
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% layer_chassis_dispatch.cpp
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% layer_chassis_dispatch.h
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% chassis.cpp
+py -3 ../../../scripts/lvl_genvk.py -registry %HEADERS_REGISTRY_PATH%/vk.xml -scripts %HEADERS_REGISTRY_PATH% chassis.h
+
 set SPIRV_TOOLS_PATH=../../third_party/shaderc/third_party/spirv-tools
 set SPIRV_TOOLS_UUID=spirv_tools_uuid.txt
 
diff --git a/build-android/android-generate.sh b/build-android/android-generate.sh
index e5bbfb5..f6de5e3 100755
--- a/build-android/android-generate.sh
+++ b/build-android/android-generate.sh
@@ -28,13 +28,19 @@
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_enum_string_helper.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_object_types.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_dispatch_table_helper.h )
-( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH thread_check.h )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH thread_safety.cpp )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH thread_safety.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH parameter_validation.cpp )
-( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH unique_objects_wrappers.h )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH parameter_validation.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_layer_dispatch_table.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_extension_helper.h )
-( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH object_tracker.cpp )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH vk_typemap_helper.h )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH object_tracker.cpp )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH object_tracker.h )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH layer_chassis_dispatch.cpp )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH layer_chassis_dispatch.h )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH chassis.cpp )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry $HEADERS_REGISTRY_PATH/vk.xml -scripts $HEADERS_REGISTRY_PATH chassis.h )
 
 SPIRV_TOOLS_PATH=../../third_party/shaderc/third_party/spirv-tools
 SPIRV_TOOLS_UUID=spirv_tools_uuid.txt
diff --git a/build-android/build.py b/build-android/build.py
index ab21c55..4cee830 100755
--- a/build-android/build.py
+++ b/build-android/build.py
@@ -208,7 +208,9 @@
       {
           'source_dir': os.path.join(shaderc_root_dir, 'glslang'),
           'dest_dir': 'third_party/shaderc/third_party/glslang',
-          'files': ['glslang/OSDependent/osinclude.h'],
+          'files': ['glslang/OSDependent/osinclude.h',
+                    'Android.mk',
+                   ],
           'dirs': [
               'SPIRV',
               'OGLCompilersDLL',
diff --git a/build-android/build_all.sh b/build-android/build_all.sh
index 0b53793..e280e86 100755
--- a/build-android/build_all.sh
+++ b/build-android/build_all.sh
@@ -50,7 +50,7 @@
 echo DEMO_BUILD_DIR="${DEMO_BUILD_DIR}"
 
 function create_APK() {
-    aapt package -f -M AndroidManifest.xml -I "$ANDROID_SDK_HOME/platforms/android-24/android.jar" -S res -F bin/$1-unaligned.apk bin/libs
+    aapt package -f -M AndroidManifest.xml -I "$ANDROID_SDK_HOME/platforms/android-26/android.jar" -S res -F bin/$1-unaligned.apk bin/libs
     # update this logic to detect if key is already there.  If so, use it, otherwise create it.
     jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android  bin/$1-unaligned.apk androiddebugkey
     zipalign -f 4 bin/$1-unaligned.apk bin/$1.apk
diff --git a/build-android/cmake/layerlib/CMakeLists.txt b/build-android/cmake/layerlib/CMakeLists.txt
index 69754b8..5c183a4 100644
--- a/build-android/cmake/layerlib/CMakeLists.txt
+++ b/build-android/cmake/layerlib/CMakeLists.txt
@@ -66,7 +66,11 @@
         ${SRC_DIR}/layers/descriptor_sets.cpp
         ${SRC_DIR}/layers/buffer_validation.cpp
         ${SRC_DIR}/layers/shader_validation.cpp
-	    ${SRC_DIR}/layers/xxhash.c)
+        ${SRC_DIR}/layers/gpu_validation.cpp
+        ${COMMON_DIR}/include/layer_chassis_dispatch.cpp
+        ${COMMON_DIR}/include/chassis.cpp
+        ${SRC_DIR}/layers/xxhash.c)
+target_compile_definitions(VkLayer_core_validation PUBLIC "BUILD_CORE_VALIDATION")
 target_include_directories(VkLayer_core_validation PRIVATE
         ${SRC_DIR}/include
         ${SRC_DIR}/layers
@@ -76,10 +80,22 @@
         ${EXTERNAL_DIR}/spirv-tools/include)
 target_link_libraries(VkLayer_core_validation PRIVATE
         log layer_utils SPIRV-Tools-prebuilt)
+if (NOT BUILD_IN_NDK)
+    set(SPIRV_OPT_LIB
+        "${SRC_DIR}/build-android/third_party/shaderc/android_test/obj/local/${ANDROID_ABI}/libSPIRV-Tools-opt.a")
+    add_library(SPIRV-Tools-opt-prebuilt STATIC IMPORTED)
+    set_target_properties(SPIRV-Tools-opt-prebuilt PROPERTIES IMPORTED_LOCATION
+        ${SPIRV_OPT_LIB})
+    target_link_libraries(VkLayer_core_validation PRIVATE
+        SPIRV-Tools-opt-prebuilt)
+endif()
 
 add_library(VkLayer_parameter_validation SHARED
         ${COMMON_DIR}/include/parameter_validation.cpp
+        ${COMMON_DIR}/include/layer_chassis_dispatch.cpp
+        ${COMMON_DIR}/include/chassis.cpp
         ${SRC_DIR}/layers/parameter_validation_utils.cpp)
+target_compile_definitions(VkLayer_parameter_validation PUBLIC "BUILD_PARAMETER_VALIDATION")
 target_include_directories(VkLayer_parameter_validation PRIVATE
         ${SRC_DIR}/include
         ${COMMON_DIR}/include
@@ -89,7 +105,10 @@
 
 add_library(VkLayer_object_tracker SHARED
         ${COMMON_DIR}/include/object_tracker.cpp
+        ${COMMON_DIR}/include/layer_chassis_dispatch.cpp
+        ${COMMON_DIR}/include/chassis.cpp
         ${SRC_DIR}/layers/object_tracker_utils.cpp)
+target_compile_definitions(VkLayer_object_tracker PUBLIC "BUILD_OBJECT_TRACKER")
 target_include_directories(VkLayer_object_tracker PRIVATE
         ${SRC_DIR}/include
         ${SRC_DIR}/layers
@@ -98,7 +117,10 @@
 target_link_libraries(VkLayer_object_tracker PRIVATE log layer_utils)
 
 add_library(VkLayer_threading SHARED
-        ${SRC_DIR}/layers/threading.cpp)
+        ${COMMON_DIR}/include/thread_safety.cpp
+        ${COMMON_DIR}/include/layer_chassis_dispatch.cpp
+        ${COMMON_DIR}/include/chassis.cpp
+target_compile_definitions(VkLayer_threading PUBLIC "BUILD_THREAD_SAFETY")
 target_include_directories(VkLayer_threading PRIVATE
         ${SRC_DIR}/include
         ${SRC_DIR}/layers
@@ -107,7 +129,9 @@
 target_link_libraries(VkLayer_threading PRIVATE log layer_utils)
 
 add_library(VkLayer_unique_objects SHARED
-        ${SRC_DIR}/layers/unique_objects.cpp)
+        ${COMMON_DIR}/include/layer_chassis_dispatch.cpp)
+        ${COMMON_DIR}/include/chassis.cpp)
+target_compile_definitions(VkLayer_object_tracker PUBLIC "LAYER_CHASSIS_CAN_WRAP_HANDLES")
 target_include_directories(VkLayer_unique_objects PRIVATE
         ${SRC_DIR}/include
         ${SRC_DIR}/layers
diff --git a/build-android/jni/Android.mk b/build-android/jni/Android.mk
index 26b237b..215c1ce 100644
--- a/build-android/jni/Android.mk
+++ b/build-android/jni/Android.mk
@@ -39,15 +39,18 @@
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/descriptor_sets.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/buffer_validation.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/shader_validation.cpp
+LOCAL_SRC_FILES += $(SRC_DIR)/layers/gpu_validation.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/convert_to_renderpass2.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/layer_chassis_dispatch.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/chassis.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/xxhash.c
 LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \
                     $(LOCAL_PATH)/$(SRC_DIR)/layers \
                     $(LOCAL_PATH)/$(LAYER_DIR)/include
-LOCAL_STATIC_LIBRARIES += layer_utils glslang SPIRV-Tools
+LOCAL_STATIC_LIBRARIES += layer_utils glslang SPIRV-Tools SPIRV-Tools-opt
 LOCAL_CPPFLAGS += -std=c++11 -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
-LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -DVK_PROTOTYPES -fvisibility=hidden
-LOCAL_LDLIBS    := -llog
+LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -DVK_PROTOTYPES -fvisibility=hidden -DBUILD_CORE_VALIDATION
+LOCAL_LDLIBS    := -llog -landroid
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
 include $(BUILD_SHARED_LIBRARY)
@@ -55,13 +58,15 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := VkLayer_parameter_validation
 LOCAL_SRC_FILES += $(LAYER_DIR)/include/parameter_validation.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/layer_chassis_dispatch.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/chassis.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/parameter_validation_utils.cpp
 LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \
                     $(LOCAL_PATH)/$(LAYER_DIR)/include \
                     $(LOCAL_PATH)/$(SRC_DIR)/layers
 LOCAL_STATIC_LIBRARIES += layer_utils
 LOCAL_CPPFLAGS += -std=c++11 -DVK_PROTOTYPES -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
-LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden
+LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden -DBUILD_PARAMETER_VALIDATION
 LOCAL_LDLIBS    := -llog
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
@@ -70,13 +75,15 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := VkLayer_object_tracker
 LOCAL_SRC_FILES += $(LAYER_DIR)/include/object_tracker.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/layer_chassis_dispatch.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/chassis.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/object_tracker_utils.cpp
 LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \
                     $(LOCAL_PATH)/$(SRC_DIR)/layers \
                     $(LOCAL_PATH)/$(LAYER_DIR)/include
 LOCAL_STATIC_LIBRARIES += layer_utils
 LOCAL_CPPFLAGS += -std=c++11 -DVK_PROTOTYPES -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
-LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden
+LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden -DBUILD_OBJECT_TRACKER
 LOCAL_LDLIBS    := -llog
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
@@ -84,13 +91,15 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := VkLayer_threading
-LOCAL_SRC_FILES += $(SRC_DIR)/layers/threading.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/thread_safety.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/layer_chassis_dispatch.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/chassis.cpp
 LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \
                     $(LOCAL_PATH)/$(SRC_DIR)/layers \
                     $(LOCAL_PATH)/$(LAYER_DIR)/include
 LOCAL_STATIC_LIBRARIES += layer_utils
 LOCAL_CPPFLAGS += -std=c++11 -DVK_PROTOTYPES -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
-LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden
+LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -fvisibility=hidden -DBUILD_THREAD_SAFETY
 LOCAL_LDLIBS    := -llog
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
@@ -98,13 +107,14 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := VkLayer_unique_objects
-LOCAL_SRC_FILES += $(SRC_DIR)/layers/unique_objects.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/layer_chassis_dispatch.cpp
+LOCAL_SRC_FILES += $(LAYER_DIR)/include/chassis.cpp
 LOCAL_C_INCLUDES += $(VULKAN_INCLUDE) \
                     $(LOCAL_PATH)/$(SRC_DIR)/layers \
                     $(LOCAL_PATH)/$(LAYER_DIR)/include
 LOCAL_STATIC_LIBRARIES += layer_utils
 LOCAL_CPPFLAGS += -std=c++11 -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
-LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -DVK_PROTOTYPES -fvisibility=hidden
+LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -DVK_PROTOTYPES -fvisibility=hidden -DLAYER_CHASSIS_CAN_WRAP_HANDLES
 LOCAL_LDLIBS    := -llog
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
@@ -128,7 +138,7 @@
 LOCAL_STATIC_LIBRARIES := googletest_main layer_utils shaderc
 LOCAL_CPPFLAGS += -std=c++11 -DVK_PROTOTYPES -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
 LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR -DNV_EXTENSIONS -DAMD_EXTENSIONS -fvisibility=hidden --include=$(THIRD_PARTY)/Vulkan-Tools/common/vulkan_wrapper.h
-LOCAL_LDLIBS := -llog
+LOCAL_LDLIBS := -llog -landroid
 LOCAL_LDFLAGS   += -Wl,-Bsymbolic
 LOCAL_LDFLAGS   += -Wl,--exclude-libs,ALL
 include $(BUILD_EXECUTABLE)
diff --git a/build-android/jni/Application.mk b/build-android/jni/Application.mk
index 3cfea11..66128c0 100644
--- a/build-android/jni/Application.mk
+++ b/build-android/jni/Application.mk
@@ -14,7 +14,8 @@
 # limitations under the License.
 
 APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
-APP_PLATFORM := android-22
+# APP_ABI := arm64-v8a   # just build for pixel2  (don't check in)
+APP_PLATFORM := android-26
 APP_STL := c++_static
 APP_MODULES := VkLayer_core_validation VkLayer_parameter_validation VkLayer_object_tracker VkLayer_threading VkLayer_unique_objects
 NDK_TOOLCHAIN_VERSION := clang
diff --git a/build-android/known_good.json b/build-android/known_good.json
index 43f335a..f5c53bc 100644
--- a/build-android/known_good.json
+++ b/build-android/known_good.json
@@ -4,37 +4,37 @@
       "name" : "shaderc",
       "url" : "https://github.com/google/shaderc.git",
       "sub_dir" : "shaderc",
-      "commit" : "38fbaeda7b34543042367547bc3cb025c9b84a9f"
+      "commit" : "419517b1595ffcf14c6098c3c1af09e7033e09df"
     },
     {
       "name" : "glslang",
       "url" : "https://github.com/KhronosGroup/glslang.git",
       "sub_dir" : "shaderc/third_party/glslang",
-      "commit" : "91ac4290bcf2cb930b4fb0981f09c00c0b6797e1"
+      "commit" : "9983f99e87ab0b6608b236ea59bcf873f90e1435"
     },
     {
       "name" : "Vulkan-Headers",
       "url" : "https://github.com/KhronosGroup/Vulkan-Headers.git",
       "sub_dir" : "Vulkan-Headers",
-      "commit" : "aaca7baef0132f5f8c8f89ee07e3a27aca52b59c"
+      "commit" : "v1.1.102"
     },
     {
       "name" : "Vulkan-Tools",
       "url" : "https://github.com/KhronosGroup/Vulkan-Tools.git",
       "sub_dir" : "Vulkan-Tools",
-      "commit" : "2e8d601de618eddf2bab8597fd140b2824a060b2"
+      "commit" : "v1.1.102"
     },
     {
       "name" : "SPIRV-Tools",
       "url" : "https://github.com/KhronosGroup/SPIRV-Tools.git",
       "sub_dir" : "shaderc/third_party/spirv-tools",
-      "commit" : "9bfe0eb25e3dfdf4f3fd86ab6c0cda009c9bd661"
+      "commit" : "0f4bf0720a9cd49d7375ae1296c874133df5ea34"
     },
     {
       "name" : "SPIRV-Headers",
       "url" : "https://github.com/KhronosGroup/SPIRV-Headers.git",
       "sub_dir" : "shaderc/third_party/spirv-tools/external/spirv-headers",
-      "commit" : "d5b2e1255f706ce1f88812217e9a554f299848af"
+      "commit" : "8bea0a266ac9b718aa0818d9e3a47c0b77c2cb23"
     }
   ]
 }
diff --git a/build-android/test_APK.sh b/build-android/test_APK.sh
index 801b16f..f1822ab 100755
--- a/build-android/test_APK.sh
+++ b/build-android/test_APK.sh
@@ -14,6 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Quiet by default
+set +x
+
+echo
+echo === Vulkan Validation Layers Tests ===
+echo Running test script: build-android/test_APK.sh
+echo
+
 #
 # Parse parameters
 #
@@ -91,7 +99,10 @@
 if [[ $filter ]]; then echo filter = "${filter}"; fi
 if [[ $serial ]]; then echo serial = "${serial}"; fi
 
-set -ev
+set -e
+
+echo
+echo Setting up...
 
 #
 # Start up
@@ -144,9 +155,15 @@
 # Re-enable exit on error
 set -e
 
+echo
+echo Installing ./bin/VulkanLayerValidationTests.apk...
+
 # Install the current build
 adb $serialFlag install -r bin/VulkanLayerValidationTests.apk
 
+echo
+echo Launching tests...
+
 # Kick off the tests with known expection list
 adb $serialFlag shell am start -a android.intent.action.MAIN -c android-intent.category.LAUNCH -n com.example.VulkanLayerValidationTests/android.app.NativeActivity --es args --gtest_filter="${filter}"
 
@@ -169,7 +186,9 @@
     adb $serialFlag logcat -d | grep "==== Tests PASSED ===="
     if [ $? -eq 0 ]
     then
+        echo
         echo VulkanLayerValidationTests PASSED!
+        echo
         exitCode=0
         break
     fi
@@ -178,7 +197,9 @@
     adb $serialFlag logcat -d | grep "==== Tests FAILED ===="
     if [ $? -eq 0 ]
     then
+        echo
         echo VulkanLayerValidationTests FAILED!
+        echo
         exitCode=1
         break
     fi
@@ -188,7 +209,9 @@
     if [ $? -eq 0 ]
     then
         exitCode=2
+        echo
         echo VulkanLayerValidationTests CRASHED!
+        echo
         break
     fi
 
@@ -214,11 +237,16 @@
 # Stop the activity
 adb $serialFlag shell am force-stop com.example.VulkanLayerValidationTests
 
+echo
+echo Fetching test output and filtered logcat text...
+
 today=$(date +%Y-%m-%d.%H:%M:%S)
 outFile="VulkanLayerValidationTests.$platform.$today.out.txt"
 errFile="VulkanLayerValidationTests.$platform.$today.err.txt"
-adb $serialFlag pull /sdcard/Android/data/com.example.VulkanLayerValidationTests/files/out.txt VulkanLayerValidationTests.$platform.$today.out.txt
-adb $serialFlag pull /sdcard/Android/data/com.example.VulkanLayerValidationTests/files/err.txt VulkanLayerValidationTests.$platform.$today.err.txt
+logFile="VulkanLayerValidationTests.$platform.$today.logcat.txt"
+adb $serialFlag pull /sdcard/Android/data/com.example.VulkanLayerValidationTests/files/out.txt $outFile
+adb $serialFlag pull /sdcard/Android/data/com.example.VulkanLayerValidationTests/files/err.txt $errFile
+adb $serialFlag logcat -d | grep VulkanLayerValidationTests > $logFile
 
 if [ -f $outFile ]; then
     echo $outFile size $(wc -c < $outFile)
@@ -228,12 +256,23 @@
     echo $errFile size $(wc -c < $errFile)
 fi
 
-echo
-echo ===== Dumping logcat of VulkanLayerValidationTests =====
-echo If the test is crashing, be sure to inspect full log for complete stack trace.
-echo "adb $serialFlag logcat -d | grep VulkanLayerValidationTests"
-echo ========================================================
-echo
-adb $serialFlag logcat -d | grep VulkanLayerValidationTests
+if [ -f $logFile ]; then
+    echo $logFile size $(wc -c < $logFile)
+fi
+
+if [ $exitCode -ne 0 ]
+then
+    echo 
+    echo VulkanLayerValidationTests result status is unsuccessful.  Dumping test output file:
+    echo =========================================================================================
+    cat $outFile
+    echo =========================================================================================
+    echo
+    echo 
+    echo Dumping logcat text, filtered by ''"VulkanLayerValidationTests"'':
+    echo =========================================================================================
+    cat $logFile
+    echo =========================================================================================
+fi
 
 exit $exitCode
diff --git a/docs/core_validation_layer.md b/docs/core_validation_layer.md
index 45ef3f7..da43b5b 100644
--- a/docs/core_validation_layer.md
+++ b/docs/core_validation_layer.md
@@ -1,44 +1,60 @@
+<!-- markdownlint-disable MD041 -->
+<!-- Copyright 2015-2019 LunarG, Inc. -->
+
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
 # VK\_LAYER\_LUNARG\_core\_validation
+
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
 The `VK_LAYER_LUNARG_core_validation` layer validates the status of descriptor sets, command buffers, shader modules, pipeline states, renderpass usage, synchronization, dynamic states and is the workhorse layer for many other types of valid usage.
 
 `VK_LAYER_LUNARG_core_validation` validates that:
 
- - the descriptor set state and pipeline state at each draw call are consistent
- - pipelines are created correctly, known when used and bound at draw time
- - descriptor sets are known and consist of valid types, formats, and layout
- - descriptor set regions are valid, bound, and updated appropriately
- - command buffers referenced are known and valid
- - command sequencing for specific state dependencies and renderpass use is correct
- - memory is available
- - dynamic state is correctly set.
+- the descriptor set state and pipeline state at each draw call are consistent
+- pipelines are created correctly, known when used and bound at draw time
+- descriptor sets are known and consist of valid types, formats, and layout
+- descriptor set regions are valid, bound, and updated appropriately
+- command buffers referenced are known and valid
+- command sequencing for specific state dependencies and renderpass use is correct
+- memory is available
+- dynamic state is correctly set.
 
 The `VK_LAYER_LUNARG_core_validation` layer will print errors if validation checks are not correctly met.  `VK_LAYER_LUNARG_core_validation` will also display the values of the objects tracked.
 
 ## Memory/Resource related functionality
+
 This layer additionally attempts to ensure that memory objects are managed correctly by the application.  These memory objects may be bound to pipelines, objects, and command buffers, and then submitted to the GPU for work. Specifically the layer validates that:
 
- - the correct memory objects have been bound
- - memory objects are specified correctly upon command buffer submittal
- - only existing memory objects are referenced
- - destroyed memory objects are not referenced
- - the application has confirmed any memory objects to be reused or destroyed have been properly unbound
- - checks texture formats and render target formats.
+- the correct memory objects have been bound
+- memory objects are specified correctly upon command buffer submittal
+- only existing memory objects are referenced
+- destroyed memory objects are not referenced
+- the application has confirmed any memory objects to be reused or destroyed have been properly unbound
+- checks texture formats and render target formats.
 
 Errors will be printed if validation checks are not correctly met and warnings if improper (but not illegal) use of memory is detected.  This validation layer also dumps all memory references and bindings for each operation.
 
 ## Shader validation functionality
+
 Checks performed by this layer apply to the VS->FS and FS->CB interfaces with the pipeline.  These checks include:
 
- - validating that all variables which are part of a shader interface are  decorated with either `spv::DecLocation` or `spv::DecBuiltin` (that is, only the SSO rendezvous-by-location model is supported)
- - emitting a warning if a location is declared only in the producing stage (useless work is being done)
- - emitting an error if a location is declared only in the consuming stage (garbage will be read).
+- validating that all variables which are part of a shader interface are  decorated with either `spv::DecLocation` or `spv::DecBuiltin` (that is, only the SSO rendezvous-by-location model is supported)
+- emitting a warning if a location is declared only in the producing stage (useless work is being done)
+- emitting an error if a location is declared only in the consuming stage (garbage will be read).
 
 A special error checking case invoked when the FS stage writes a built-in corresponding to the legacy `gl_FragColor`.  In this case, an error is emitted if
 
-  - the FS also writes any user-defined output
-  - the CB has any attachment with a `UINT` or `SINT` type.
+- the FS also writes any user-defined output
+- the CB has any attachment with a `UINT` or `SINT` type.
 
 These extra checks are to ensure that the legacy broadcast of `gl_FragColor` to all bound color attachments is well-defined.
 
 ## Swapchain validation functionality
-This area of functionality validates the use of the WSI (Window System Integration) "swapchain" extensions (i.e., `VK_EXT_KHR_swapchain` and `VK_EXT_KHR_device_swapchain`).
+
+This area of functionality validates the use of the WSI (Window System Integration) "swapchain" extensions (e.g., `VK_EXT_KHR_swapchain` and `VK_EXT_KHR_device_swapchain`).
diff --git a/docs/gpu_validation.md b/docs/gpu_validation.md
new file mode 100644
index 0000000..ac1d1d2
--- /dev/null
+++ b/docs/gpu_validation.md
@@ -0,0 +1,771 @@
+<!-- markdownlint-disable MD041 -->
+<!-- Copyright 2015-2019 LunarG, Inc. -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
+# GPU-Assisted Validation
+
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+
+GPU-Assisted validation is implemented in the SPIR-V Tools optimizer and the `VK_LAYER_LUNARG_core_validation` layer.
+This document covers the design of the layer portion of the implementation.
+
+## Basic Operation
+
+The basic operation of GPU-Assisted validation is comprised of instrumenting shader code to perform run-time checking in shaders and
+reporting any error conditions to the layer.
+The layer then reports the errors to the user via the same reporting mechanisms used by the rest of the validation system.
+
+The layer instruments the shaders by passing the shader's SPIR-V bytecode to the SPIR-V optimizer component and
+instructs the optimizer to perform an instrumentation pass to add the additional instructions to perform the run-time checking.
+The layer then passes the resulting modified SPIR-V bytecode to the driver as part of the process of creating a ShaderModule.
+
+As the shader is executed, the instrumented shader code performs the run-time checks.
+If a check detects an error condition, the instrumentation code writes an error record into the GPU's device memory.
+This record is small and is on the order of a dozen 32-bit words.
+Since multiple shader stages and multiple invocations of a shader can all detect errors, the instrumentation code
+writes error records into consecutive memory locations as long as there is space available in the pre-allocated block of device memory.
+
+The layer inspects this device memory block after completion of a queue submission.
+If the GPU had written an error record to this memory block,
+the layer analyzes this error record and constructs a validation error message
+which is then reported in the same manner as other validation messages.
+If the shader was compiled with debug information (source code and SPIR-V instruction mapping to source code lines), the layer
+also provides the line of shader source code that provoked the error as part of the validation error message.
+
+## GPU-Assisted Validation Checks
+
+The initial release (Jan 2019) of GPU-Assisted Validation includes checking for out-of-bounds descriptor array indexing
+for image/texel descriptor types.
+
+Future releases are planned to add checking for other hazards such as proper population of descriptors when using the
+`descriptorBindingPartiallyBound` feature of the `VK_EXT_descriptor_indexing` extension.
+
+### Out-of-Bounds(OOB) Descriptor Array Indexing
+
+Checking for correct indexing of descriptor arrays is sometimes referred to as "bind-less validation".
+It is called "bind-less" because a binding in a descriptor set may contain an array of like descriptors.
+And unless there is a constant or compile-time indication of which descriptor in the array is selected,
+the descriptor binding status is considered to be ambiguous, leaving the actual binding to be determined at run-time.
+
+As an example, a fragment shader program may use a variable to index an array of combined image samplers.
+Such a line might look like:
+
+```glsl
+uFragColor = light * texture(tex[tex_ind], texcoord.xy);
+```
+
+The array of combined image samplers is `tex` and has 6 samplers in the array.
+The complete validation error message issued when `tex_ind` indexes past the array is:
+
+```terminal
+ERROR : VALIDATION - Message Id Number: 0 | Message Id Name: UNASSIGNED-Image descriptor index out of bounds
+        Index of 6 used to index descriptor array of length 6.  Command buffer (CubeDrawCommandBuf)(0xbc24b0).
+        Pipeline (0x45). Shader Module (0x43). Shader Instruction Index = 108.  Stage = Fragment.
+        Fragment coord (x,y) = (419.5, 254.5). Shader validation error occurred in file:
+        /home/user/src/Vulkan-ValidationLayers/external/Vulkan-Tools/cube/cube.frag at line 45.
+45:    uFragColor = light * texture(tex[tex_ind], texcoord.xy);
+```
+
+## GPU-Assisted Validation Options
+
+Here are the options related to activating GPU-Assisted Validation:
+
+1. Enable GPU-Assisted Validation - GPU-Assisted Validation is off by default and must be enabled.
+
+    GPU-Assisted Validation is disabled by default because the shader instrumentation may introduce significant
+    shader performance degradation and additional resource consumption.
+    GPU-Assisted Validation requires additional resources such as device memory and descriptors.
+    It is desirable for the user to opt-in to this feature because of these requirements.
+    In addition, there are several limitations that may adversely affect application behavior,
+    as described later in this document.
+
+2. Reserve a Descriptor Set Binding Slot - Modifies the value of the `VkPhysicalDeviceLimits::maxBoundDescriptorSets`
+   property to return a value one less than the actual device's value to "reserve" a descriptor set binding slot for use by GPU validation.
+
+   This option is likely only of interest to applications that dynamically adjust their descriptor set bindings to adjust for
+   the limits of the device.
+
+### Enabling and Specifying Options with a Configuration File
+
+The existing layer configuration file mechanism can be used to enable GPU-Assisted Validation.
+This mechanism is described on the
+[LunarXchange website](https://vulkan.lunarg.com/doc/sdk/latest/windows/layer_configuration.html),
+in the "Layers Overview and Configuration" document.
+
+To turn on GPU validation, add the following to your layer settings file, which is often
+named `vk_layer_settings.txt`.
+
+```code
+lunarg_core_validation.gpu_validation = all
+```
+
+To turn on GPU validation and request to reserve a binding slot:
+
+```code
+lunarg_core_validation.gpu_validation = all,reserve_binding_slot
+```
+
+Some platforms do not support configuration of the validation layers with this configuration file.
+Programs running on these platforms must then use the programmatic interface.
+
+### Enabling and Specifying Options with the Programmatic Interface
+
+The `VK_EXT_validation_features` extension can be used to enable GPU-Assisted Validation at CreateInstance time.
+
+Here is sample code illustrating how to enable it:
+
+```C
+VkValidationFeatureEnableEXT enables[] = {VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT};
+VkValidationFeaturesEXT features = {};
+features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+features.enabledValidationFeatureCount = 1;
+features.pEnabledValidationFeatures = enables;
+
+VkInstanceCreateInfo info = {};
+info.pNext = &features;
+```
+
+Use the `VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT` enum to reserve a binding slot.
+
+## GPU-Assisted Validation Limitations
+
+There are several limitations that may impede the operation of GPU-Assisted Validation:
+
+### Vulkan 1.1
+
+Vulkan 1.1 or later is required because the GPU instrumentation code uses SPIR-V 1.3 features.
+Vulkan 1,1 is required to ensure that SPIR-V 1.3 is available.
+
+### Descriptor Types
+
+The current implementation works with image and texel descriptor types.
+A complete list appears later in this document.
+
+### Descriptor Set Binding Limit
+
+This is probably the most important limitation and is related to the
+`VkPhysicalDeviceLimits::maxBoundDescriptorSets` device limit.
+
+When applications use all the available descriptor set binding slots,
+GPU-Assisted Validation cannot be performed because it needs a descriptor set to
+locate the memory for writing the error report record.
+
+This problem is most likely to occur on devices, often mobile, that support only the
+minimum required value for `VkPhysicalDeviceLimits::maxBoundDescriptorSets`, which is 4.
+Some applications may be written to use 4 slots since this is the highest value that
+is guaranteed by the specification.
+When such an application using 4 slots runs on a device with only 4 slots,
+then GPU-Assisted Validation cannot be performed.
+
+In this implementation, this condition is detected and gracefully recovered from by
+building the graphics pipeline with non-instrumented shaders instead of instrumented ones.
+An error message is also displayed informing the user of the condition.
+
+Applications don't have many options in this situation and it is anticipated that
+changing the application to free a slot is difficult.
+
+### Device Memory
+
+GPU-Assisted Validation does allocate device memory for the error report buffers.
+This can lead to a greater chance of memory exhaustion, especially in cases where
+the application is trying to use all of the available memory.
+The extra memory allocations are also not visible to the application, making it
+impossible for the application to account for them.
+
+If GPU-Assisted Validation device memory allocations fail, the device could become
+unstable because some previously-built pipelines may contain instrumented shaders.
+This is a condition that is nearly impossible to recover from, so the layer just
+prints an error message and refrains from any further allocations or instrumentations.
+There is a reasonable chance to recover from these conditions,
+especially if the instrumentation does not write any error records.
+
+### Descriptors
+
+This is roughly the same problem as the device memory problem mentioned above,
+but for descriptors.
+Any failure to allocate a descriptor set means that the instrumented shader code
+won't have a place to write error records, resulting in unpredictable device
+behavior.
+
+### Other Device Limits
+
+This implementation uses additional resources that may count against the following limits,
+and possibly others:
+
+* `maxMemoryAllocationCount`
+* `maxBoundDescriptorSets`
+* `maxPerStageDescriptorStorageBuffers`
+* `maxPerStageResources`
+* `maxDescriptorSetStorageBuffers`
+* `maxFragmentCombinedOutputResources`
+
+The implementation does not take steps to avoid exceeding these limits
+and does not update the tracking performed by other validation functions.
+
+### A Note About the `VK_EXT_buffer_device_address` Extension
+
+The recently introduced `VK_EXT_buffer_device_address` extension can be used
+to implement GPU-Assisted Validation without some of the limitations described above.
+This approach would use this extension to obtain a GPU device pointer to a storage
+buffer and make it available to the shader via a specialization constant.
+This technique removes the need to create descriptors, use a descriptor set slot,
+modify pipeline layouts, etc, and would relax some of the limitations listed above.
+
+This alternate implementation is under consideration.
+
+## GPU-Assisted Validation Internal Design
+
+This section may be of interest to readers who are interested on how GPU-Assisted Validation is implemented.
+It isn't necessarily required for using the feature.
+
+### General
+
+In general, the implementation does:
+
+* For each draw call, allocate a block of device memory to hold a single debug output record written by the
+    instrumented shader code.
+    There is a device memory manager to handle this efficiently.
+
+    There is probably little advantage in providing a larger buffer in order to obtain more debug records.
+    It is likely, especially for fragment shaders, that multiple errors occurring near each other have the same root cause.
+
+    A block is allocated on a per draw basis to make it possible to associate a shader debug error record with
+    a draw within a command buffer.
+    This is done partly to give the user more information in the error report, namely the command buffer handle/name and the draw within that command buffer.
+    An alternative design allocates this block on a per-device or per-queue basis and should work.
+    However, it is not possible to identify the command buffer that causes the error if multiple command buffers
+    are submitted at once.
+* For each draw call, allocate a descriptor set and update it to point to the block of device memory just allocated.
+    There is a descriptor set manager to handle this efficiently.
+    Also make an additional call down the chain to create a bind descriptor set command to bind our descriptor set at the desired index.
+    This has the effect of binding the device memory block belonging to this draw so that the GPU instrumentation
+    writes into this buffer for when the draw is executed.
+    The end result is that each draw call has its own device memory block containing GPU instrumentation error
+    records, if any occurred while executing that draw.
+* Determine the descriptor set binding index that is eventually used to bind the descriptor set just allocated and updated.
+    Usually, it is `VkPhysicalDeviceLimits::maxBoundDescriptorSets` minus one.
+    For devices that have a very high or no limit on this bound, pick an index that isn't too high, but above most other device
+    maxima such as 32.
+* When creating a ShaderModule, pass the SPIR-V bytecode to the SPIR-V optimizer to perform the instrumentation pass.
+    Pass the desired descriptor set binding index to the optimizer via a parameter so that the instrumented
+    code knows which descriptor to use for writing error report data to the memory block.
+    Use the instrumented bytecode to create the ShaderModule.
+* For all pipeline layouts, add our descriptor set to the layout, at the binding index determined earlier.
+    Fill any gaps with empty descriptor sets.
+
+    If the incoming layout already has a descriptor set placed at our desired index, the layer must not add its
+    descriptor set to the layout, replacing the one in the incoming layout.
+    Instead, the layer leaves the layout alone and later replaces the instrumented shaders with
+    non-instrumented ones when the pipeline layout is later used to create a graphics pipeline.
+    The layer issues an error message to report this condition.
+* When creating a GraphicsPipeline, check to see if the pipeline is using the debug binding index.
+    If it is, replace the instrumented shaders in the pipeline with non-instrumented ones.
+* After calling QueueSubmit, perform a wait on the queue to allow the queue to finish executing.
+    Then map and examine the device memory block for each draw that was submitted.
+    If any debug record is found, generate a validation error message for each record found.
+
+The above describes only the high-level details of GPU-Assisted Validation operation.
+More detail is found in the discussion of the individual hooked functions below.
+
+### Initialization
+
+When the core validation layer loads, it examines the user options from both the layer settings file and the
+`VK_EXT_validation_features` extension.
+Note that it also processes the subsumed `VK_EXT_validation_flags` extension for simple backwards compatibility.
+From these options, the layer sets instance-scope flags in the core validation layer tracking data to indicate if
+GPU-Assisted Validation has been requested, along with any other associated options.
+
+### "Calling Down the Chain"
+
+Much of the GPU-Assisted Validation implementation involves making "application level" Vulkan API
+calls outside of the application's API usage to create resources and perform its required operations
+inside of the core validation layer.
+These calls are not routed up through the top of the loader/layer/driver call stack via the loader.
+Instead, they are simply dispatched via the core validation layer's dispatch table.
+
+These calls therefore don't pass through core validation or any other validation layers that may be
+loaded/dispatched prior to code validation.
+This doesn't present any particular problem, but it does raise some issues:
+
+* The additional API calls are not fully validated
+
+  This implies that this additional code may never be checked for validation errors.
+  To address this, the code can "just" be written carefully so that it is "valid" Vulkan,
+  which is hard to do.
+
+  Or, this code can be checked by loading a core validation layer with
+  GPU validation enabled on top of "normal" standard validation in the
+  layer stack, which effectively validates the API usage of this code.
+  This sort of checking is performed by layer developers to check that the additional
+  Vulkan usage is valid.
+
+  This validation can be accomplished by:
+  
+  * Building the core validation layer with a hack to force GPU-Assisted Validation to be enabled.
+  Can't use the exposed mechanisms because we probably don't want it on twice.
+  * Rename this layer binary to something else like "core_validation2" to keep it apart from the
+  "normal" core validation.
+  * Create a new JSON file with the new layer name.
+  * Set up the layer stack so that the "core_validation2" layer is on top of or before the standard validation
+  layer
+  * Then run tests and check for validation errors pointing to API usage in the "core_validation2" layer.
+
+  This should only need to be done after making any major changes to the implementation.
+
+  Another approach involves capturing an application trace with `vktrace` and then playing
+  it back with `vkreplay`.
+
+* The additional API calls are not state-tracked
+
+  This means that things like device memory allocations and descriptor allocations are not
+  tracked and do not show up in any of the bookkeeping performed by the validation layers.
+  For example, any device memory allocation performed by GPU-Assisted Validation won't be
+  counted towards the maximum number of allocations allowed by a device.
+  This could lead to an early allocation failure that is not accompanied by a validation error.
+
+  This shortcoming is left as not addressed in this implementation because it is anticipated that
+  a later implementation of GPU-Assisted Validation using the `VK_EXT_buffer_device_address`
+  extension will have less of a need to allocate these
+  tracked resources and it therefore becomes less of an issue.
+
+### Code Structure and Relationship to the Core Validation Layer
+
+The GPU-Assisted Validation code is largely contained in one
+[file](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/master/layers/gpu_validation.cpp), with "hooks" in
+the other core validation code that call functions in this file.
+These hooks in the core validation code look something like this:
+
+```C
+if (GetEnables(dev_data)->gpu_validation) {
+    GpuPreCallRecordDestroyPipeline(dev_data, pipeline_state);
+}
+```
+
+The GPU-Assisted Validation code is linked into the shared library for the core validation layer.
+
+#### Review of Core Validation Code Structure
+
+Each function for a Vulkan API command intercepted in the core validation layer is usually split up
+into several decomposed functions in order to organize the implementation.
+These functions take the form of:
+
+* PreCallValidate&lt;foo&gt;: Perform validation steps before calling down the chain
+* PostCallValidate&lt;foo&gt;: Perform validation steps after calling down the chain
+* PreCallRecord&lt;foo&gt;: Perform state recording before calling down the chain
+* PostCallRecord&lt;foo&gt;: Perform state recording after calling down the chain
+
+The GPU-Assisted Validation functions follow this pattern not by hooking into the top-level core validation API shim, but
+by hooking one of these decomposed functions.
+In a few unusual cases, the GPU-Assisted Validation function "takes over" the call to the driver (down the chain) and so
+must hook the top-level API shim.
+These functions deviate from the above naming convention to make their purpose more evident.
+
+The design of each hooked function follows:
+
+#### GpuPreCallRecordCreateDevice
+
+* Modify the `VkPhysicalDeviceFeatures` to turn on two additional physical device features:
+  * `fragmentStoresAndAtomics`
+  * `vertexPipelineStoresAndAtomics`
+
+#### GpuPostCallRecordCreateDevice
+
+* Determine and record (save in device state) the desired descriptor set binding index.
+* Initialize device memory manager
+  * Determine error record block size based on the maximum size of the error record and alignment limits of the device.
+* Initialize descriptor set manager
+* Make a descriptor set layout to describe our descriptor set
+* Make a descriptor set layout to describe a "dummy" descriptor set that contains no descriptors
+  * This is used to "pad" pipeline layouts to fill any gaps between the used bind indices and our bind index
+* Record these objects in the per-device state
+
+#### GpuPreCallRecordDestroyDevice
+
+* Destroy descriptor set layouts created in CreateDevice
+* Clean up descriptor set manager
+* Clean up device memory manager
+* Clean up device state
+
+#### GpuAllocateValidationResources
+
+* For each Draw or Dispatch call:
+  * Get a descriptor set from the descriptor set manager
+  * Get a device memory block from the device memory manager
+  * Update (write) the descriptor set with the memory info
+  * Check to see if the layout for the pipeline just bound is using our selected bind index
+  * If no conflict, add an additional command to the command buffer to bind our descriptor set at our selected index
+* Record the above objects in the per-CB state
+Note that the Draw and Dispatch calls include vkCmdDraw, vkCmdDrawIndexed, vkCmdDrawIndirect, vkCmdDrawIndexedIndirect, vkCmdDispatch, and vkCmdDispatchIndirect. 
+
+#### GpuPreCallRecordFreeCommandBuffers
+
+* For each command buffer:
+  * Give the memory blocks back to the device memory manager
+  * Give the descriptor sets back to the descriptor set manager
+  * Clean up CB state
+
+#### GpuOverrideDispatchCreateShaderModule
+
+This function is called from CreateShaderModule and can't really be called from one of the decomposed functions
+because it replaces the SPIR-V, which requires modifying the bytecode passed down to the driver.
+This routine sets up to call the SPIR-V optimizer to run the "BindlessCheckPass", replacing the original SPIR-V with the instrumented SPIR-V
+which is then used in the call down the chain to CreateShaderModule.
+
+This function generates a "unique shader ID" that is passed to the SPIR-V optimizer,
+which the instrumented code puts in the debug error record to identify the shader.
+This ID is returned by this function so it can be recorded in the shader module at PostCallRecord time.
+It would have been convenient to use the shader module handle returned from the driver to use as this shader ID.
+But the shader needs to be instrumented before creating the shader module and therefore the handle is not available to use
+as this ID to pass to the optimizer.
+Therefore, the layer keeps a "counter" in per-device state that is incremented each time a shader is instrumented
+to generate unique IDs.
+This unique ID is given to the SPIR-V optimizer and is stored in the shader module state tracker after the shader module is created, which creates the necessary association between the ID and the shader module.
+
+The process of instrumenting the SPIR-V also includes passing the selected descriptor set binding index
+to the SPIR-V optimizer which the instrumented
+code uses to locate the memory block used to write the debug error record.
+An instrumented shader is now "hard-wired" to write error records via the descriptor set at that binding
+if it detects an error.
+This implies that the instrumented shaders should only be allowed to run when the correct bindings are in place.
+
+The original SPIR-V bytecode is left stored in the shader module tracking data.
+This is important because the layer may need to replace the instrumented shader with the original shader if, for example,
+there is a binding index conflict.
+The application cannot destroy the shader module until it has used the shader module to create the pipeline.
+This ensures that the original SPIR-V bytecode is available if we need it to replace the instrumented shader.
+
+#### GpuOverrideDispatchCreatePipelineLayout
+
+This is another function that replaces the parameters and so can't be called from a decomposed function.
+
+* Check for a descriptor set binding index conflict.
+  * If there is one, issue an error message and leave the pipeline layout unmodified
+  * If no conflict, for each pipeline layout:
+    * Create a new pipeline layout
+    * Copy the original descriptor set layouts into the new pipeline layout
+    * Pad the new pipeline layout with dummy descriptor set layouts up to but not including the last one
+    * Add our descriptor set layout as the last one in the new pipeline layout
+* Create the pipeline layouts by calling down the chain with the original or modified create info
+
+
+#### GpuPostCallQueueSubmit
+
+* Submit a command buffer containing a memory barrier to make GPU writes available to the host domain.
+* Call QueueWaitIdle.
+* For each primary and secondary command buffer in the submission:
+  * Call a helper function to process the instrumentation debug buffers (described later)
+
+#### GpuPreCallValidateCmdWaitEvents
+
+* Report an error about a possible deadlock if CmdWaitEvents is recorded with VK_PIPELINE_STAGE_HOST_BIT set.
+
+#### GpuPreCallRecordCreateGraphicsPipelines
+
+* Examine the pipelines to see if any use the debug descriptor set binding index
+* For those that do:
+  * Create non-instrumented shader modules from the saved original SPIR-V
+  * Modify the CreateInfo data to use these non-instrumented shaders.
+    * This prevents instrumented shaders from using the application's descriptor set.
+
+#### GpuPostCallRecordCreateGraphicsPipelines
+
+* For every shader in the pipeline:
+  * Destroy the shader module created in GpuPreCallRecordCreateGraphicsPipelines, if any
+    * These are found in the CreateInfo used to create the pipeline and not in the shader_module
+  * Create a shader tracking record that saves:
+    * shader module handle
+    * unique shader id
+    * graphics pipeline handle
+    * shader bytecode if it contains debug info
+
+This tracker is used to attach the shader bytecode to the shader in case it is needed
+later to get the shader source code debug info.
+
+The current shader module tracker in core validation stores the bytecode,
+but this tracker has the same life cycle as the shader module itself.
+It is possible for the application to destroy the shader module after
+creating graphics pipeline and before submitting work that uses the shader,
+making the shader bytecode unavailable if needed for later analysis.
+Therefore, the bytecode must be saved at this opportunity.
+
+This tracker exists as long as the graphics pipeline exists,
+so the graphics pipeline handle is also stored in this tracker so that it can
+be looked up when the graphics pipeline is destroyed.
+At that point, it is safe to free the bytecode since the pipeline is never used again.
+
+#### GpuPreCallRecordDestroyPipeline
+
+* Find the shader tracker(s) with the graphics pipeline handle and free the tracker, along with any bytecode it has stored in it.
+
+### Shader Instrumentation Scope
+
+The shader instrumentation process performed by the SPIR-V optimizer applies descriptor index bounds checking
+to descriptors of the following types:
+
+    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
+    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
+    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
+    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
+
+Instrumentation is applied to the following SPIR-V operations:
+
+    OpImageSampleImplicitLod
+    OpImageSampleExplicitLod
+    OpImageSampleDrefImplicitLod
+    OpImageSampleDrefExplicitLod
+    OpImageSampleProjImplicitLod
+    OpImageSampleProjExplicitLod
+    OpImageSampleProjDrefImplicitLod
+    OpImageSampleProjDrefExplicitLod
+    OpImageGather
+    OpImageDrefGather
+    OpImageQueryLod
+    OpImageSparseSampleImplicitLod
+    OpImageSparseSampleExplicitLod
+    OpImageSparseSampleDrefImplicitLod
+    OpImageSparseSampleDrefExplicitLod
+    OpImageSparseSampleProjImplicitLod
+    OpImageSparseSampleProjExplicitLod
+    OpImageSparseSampleProjDrefImplicitLod
+    OpImageSparseSampleProjDrefExplicitLod
+    OpImageSparseGather
+    OpImageSparseDrefGather
+    OpImageFetch
+    OpImageRead
+    OpImageQueryFormat
+    OpImageQueryOrder
+    OpImageQuerySizeLod
+    OpImageQuerySize
+    OpImageQueryLevels
+    OpImageQuerySamples
+    OpImageSparseFetch
+    OpImageSparseRead
+    OpImageWrite
+
+### Shader Instrumentation Error Record Format
+
+The instrumented shader code generates "error records" in a specific format.
+
+This description includes the support for future GPU-Assisted Validation features
+such as checking for uninitialized descriptors in the partially-bound scenario.
+These items are not used in the current implementation for descriptor array
+bounds checking, but are provided here to complete the description of the
+error record format.
+
+The format of this buffer is as follows:
+
+```C
+struct DebugOutputBuffer_t
+{
+   uint DataWrittenLength;
+   uint Data[];
+}
+```
+
+`DataWrittenLength` is the number of uint32_t words that have been attempted to be written.
+It should be initialized to 0.
+
+The `Data` array is the uint32_t words written by the shaders of the pipeline to record bindless validation errors.
+All elements of `Data` should be initialized to 0.
+Note that the `Data` array has runtime length.
+The shader queries the length of the `Data` array to make sure that it does not write past the end of `Data`.
+The shader only writes complete records.
+The layer uses the length of `Data` to control the number of records written by the shaders.
+
+The `DataWrittenLength` is atomically updated by the shaders so that shaders do not overwrite each others data.
+The shader takes the value it gets from the atomic update.
+If the value plus the record length is greater than the length of `Data`, it does not write the record.
+
+Given this protocol, the value in `DataWrittenLength` is not very meaningful if it is greater than the length of `Data`.
+However, the format of the written records plus the fact that `Data` is initialized to 0 should be enough to determine
+the records that were written.
+
+### Record Format
+
+The format of an output record is the following:
+
+    Word 0: Record size
+    Word 1: Shader ID
+    Word 2: Instruction Index
+    Word 3: Stage
+    <Stage-Specific Words>
+    <Validation-Specific Words>
+
+The Record Size is the number of words in this record, including the the Record Size.
+
+The Shader ID is a handle that was provided by the layer when the shader was instrumented.
+
+The Instruction Index is the instruction within the original function at which the error occurred.
+For bindless, this will be the instruction which consumes the descriptor in question,
+or the instruction that consumes the OpSampledImage that consumes the descriptor.
+
+The Stage is the integer value used in SPIR-V for each of the Graphics Execution Models:
+
+| Stage  | Value |
+|--------|:-----:|
+|Vertex  |0      |
+|TessCtrl|1      |
+|TessEval|2      |
+|Geometry|3      |
+|Fragment|4      |
+|Compute |5      |
+
+### Stage Specific Words
+
+These are words that identify which "instance" of the shader the validation error occurred in.
+Here are words for each stage:
+
+| Stage  | Word 0           | Word 1     |
+|--------|------------------|------------|
+|Vertex  |VertexID          |InstanceID  |
+|Tess*   |InvocationID      |unused      |
+|Geometry|PrimitiveID       |InvocationID|
+|Fragment|FragCoord.x       |FragCoord.y |
+|Compute |GlobalInvocationID|unused      |
+
+"unused" means not relevant, but still present.
+
+### Validation-Specific Words
+
+These are words that are specific to the validation being done.
+For bindless validation, they are variable.
+
+The first word is the Error Code.
+
+For the *OutOfBounds errors, two words will follow: Word0:DescriptorIndex, Word1:DescriptorArrayLength
+
+For the *Uninitialized errors, one word will follow: Word0:DescriptorIndex
+
+| Error                       | Code | Word 0         | Word 1                |
+|-----------------------------|:----:|----------------|-----------------------|
+|IndexOutOfBounds             |0     |Descriptor Index|Descriptor Array Length|
+|DescriptorUninitialized      |1     |Descriptor Index|unused                 |
+
+So the words written for an image descriptor bounds error in a fragment shader is:
+
+    Word 0: Record size (9)
+    Word 1: Shader ID
+    Word 2: Instruction Index
+    Word 3: Stage (4:Fragment)
+    Word 4: FragCoord.x
+    Word 5: FragCoord.y
+    Word 6: Error (0: ImageIndexOutOfBounds)
+    Word 7: DescriptorIndex
+    Word 8: DescriptorArrayLength
+
+If another error is encountered, that record is written starting at Word 10, if the whole record will not overflow Data.
+If overflow will happen, no words are written..
+
+The validation layer can continue to read valid records until it sees a Record Length of 0 or the end of Data is reached.
+
+#### Programmatic interface
+
+The programmatic interface for the above informal description is codified in the
+[SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools) repository in file
+[`instrument.hpp`](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/include/spirv-tools/instrument.hpp).
+It consists largely of integer constant definitions for the codes and values mentioned above and
+offsets into the record for locating each item.
+
+## GPU-Assisted Validation Error Report
+
+This is a fairly simple process of mapping the debug report buffer associated with
+each draw in the command buffer that was just submitted and looking to see if the GPU instrumentation
+code wrote anything.
+Each draw in the command buffer should have a corresponding result buffer in the command buffer's list of result buffers.
+The report generating code loops through the result buffers, maps each of them, checks for errors, and unmaps them.
+The layer clears the buffer to zeros when it is allocated and after processing any
+buffer that was written to.
+The instrumented shader code expects these buffers to be cleared to zeros before it
+writes to them.
+
+The layer then prepares a "common" validation error message containing:
+
+* command buffer handle - This is easily obtained because we are looping over the command
+  buffers just submitted.
+* draw number - keep track of how many draws we've processed for a given command buffer.
+* pipeline handle - The shader tracker discussed earlier contains this handle
+* shader module handle - The "Shader ID" (Word 1 in the record) is used to lookup
+  the shader tracker which is then used to obtain the shader module and pipeline handles
+* instruction index - This is the SPIR-V instruction index where the invalid array access occurred.
+  It is not that useful by itself, since the user would have to use it to locate a SPIR-V instruction
+  in a SPIR-V disassembly and somehow relate it back to the shader source code.
+  But it could still be useful to some and it is easy to report.
+  The user can build the shader with debug information to get source-level information.
+
+For all objects, the layer also looks up the objects in the Debug Utils object name map in
+case the application used that extension to name any objects.
+If a name exists for that object, it is included in the error message.
+
+The layer then adds on error message text obtained from decoding the stage-specific and
+validation-specific data as described earlier.
+
+This completes the error report when there is no source-level debug information in the shader.
+
+### Source-Level Debug Information
+
+This is one of the more complicated and code-heavy parts of the GPU-Assisted Validation feature
+and all it really does is display source-level information when the shader is compiled
+with debugging info (`-g` option in the case of `glslangValidator`).
+
+The process breaks down into two steps:
+
+#### OpLine Processing
+
+The SPIR-V generator (e.g., glslangValidator) places an OpLine SPIR-V instruction in the
+shader program ahead of code generated for each source code statement.
+The OpLine instruction contains the filename id (for an OpString),
+the source code line number and the source code column number.
+It is possible to have two source code statements on the same line in the source file,
+which explains the need for the column number.
+
+The layer scans the SPIR-V looking for the last OpLine instruction that appears before the instruction
+at the instruction index obtained from the debug report.
+This OpLine then contains the correct filename id, line number, and column number of the
+statement causing the error.
+The filename itself is obtained by scanning the SPIR-V again for an OpString instruction that
+matches the id from the OpLine.
+This OpString contains the text string representing the filename.
+This information is added to the validation error message.
+
+For online compilation when there is no "file", only the line number information is reported.
+
+#### OpSource Processing
+
+The SPIR-V built with source-level debug info also contains OpSource instructions that
+have a string containing the source code, delimited by newlines.
+Due to possible pre-processing, the layer just cannot simply use the source file line number
+from the OpLine to index into this set of source code lines.
+
+Instead, the correct source code line is found by first locating the "#line" directive in the
+source that specifies a line number closest to and less than the source line number reported
+by the OpLine located in the previous step.
+The correct "#line" directive must also match its filename, if specified,
+with the filename from the OpLine.
+
+Then the difference between the "#line" line number and the OpLine line number is added
+to the place where the "#line" was found to locate the actual line of source, which is
+then added to the validation error message.
+
+For example, if the OpLine line number is 15, and there is a "#line 10" on line 40
+in the OpSource source, then line 45 in the OpSource contains the correct source line.
+
+## GPU-Assisted Validation Testing
+
+Validation Layer Tests (VLTs) exist for GPU-Assisted Validation.
+They cannot be run with the "mock ICD" in headless CI environments because they need to
+actually execute shaders.
+But they are still useful to run on real devices to check for regressions.
+
+There isn't anything else that remarkable or different about these tests.
+They activate GPU-Assisted Validation via the programmatic
+interface as described earlier.
+
+The tests exercise the extraction of source code information when the shader
+is built with debug info.
diff --git a/docs/object_tracker_layer.md b/docs/object_tracker_layer.md
index 4f64f46..8629d00 100644
--- a/docs/object_tracker_layer.md
+++ b/docs/object_tracker_layer.md
@@ -1,12 +1,25 @@
+<!-- markdownlint-disable MD041 -->
+<!-- Copyright 2015-2019 LunarG, Inc. -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
 # VK\_LAYER\_LUNARG\_object\_tracker
+
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+
 The `VK_LAYER_LUNARG_object_tracker` layer tracks all Vulkan objects. Object lifetimes are validated along with issues related to unknown objects and object destruction and cleanup.
 
 All Vulkan dispatchable and non-dispatchable objects are tracked by the `VK_LAYER_LUNARG_object_tracker` layer.
 
 This layer validates that:
 
- - only known objects are referenced and destroyed
- - lookups are performed only on objects being tracked
- - objects are correctly freed/destroyed.
+- only known objects are referenced and destroyed
+- lookups are performed only on objects being tracked
+- objects are correctly freed/destroyed.
 
 The `VK_LAYER_LUNARG_object_tracker` layer will print errors if validation checks are not correctly met and warnings if improper reference of objects is detected.
diff --git a/docs/parameter_validation_layer.md b/docs/parameter_validation_layer.md
index 1c238d3..a8dd745 100644
--- a/docs/parameter_validation_layer.md
+++ b/docs/parameter_validation_layer.md
@@ -1,8 +1,21 @@
+<!-- markdownlint-disable MD041 -->
+<!-- Copyright 2015-2019 LunarG, Inc. -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
 # VK\_LAYER\_LUNARG\_parameter\_validation
+
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+
 The `VK_LAYER_LUNARG_parameter_validation` validation layer checks the input parameters to API calls for validity. This layer performs the following tasks:
 
- - validation of structures; structures are recursed if necessary
- - validation of enumerated type values
- - null pointer conditions
- - stateless valid usage checks
- - validation of `VkResult`.
+- validation of structures; structures are recursed if necessary
+- validation of enumerated type values
+- null pointer conditions
+- stateless valid usage checks
+- validation of `VkResult`.
diff --git a/docs/threading_layer.md b/docs/threading_layer.md
index 9babd2b..1d66196 100644
--- a/docs/threading_layer.md
+++ b/docs/threading_layer.md
@@ -1,2 +1,13 @@
+<!-- markdownlint-disable MD041 -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
 # VK\_LAYER\_GOOGLE\_threading
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+
 The `VK_LAYER_GOOGLE_threading` layer checks multi-threading of API calls for validity.  Checks performed by this layer include ensuring that only one thread at a time uses an object in free-threaded API calls.
diff --git a/docs/unique_objects_layer.md b/docs/unique_objects_layer.md
index 4562644..75f3b14 100644
--- a/docs/unique_objects_layer.md
+++ b/docs/unique_objects_layer.md
@@ -1,7 +1,18 @@
+<!-- markdownlint-disable MD041 -->
+[![Khronos Vulkan][1]][2]
+
+[1]: https://vulkan.lunarg.com/img/Vulkan_100px_Dec16.png "https://www.khronos.org/vulkan/"
+[2]: https://www.khronos.org/vulkan/
+
 # VK\_LAYER\_GOOGLE\_unique\_objects
+[![Creative Commons][3]][4]
+
+[3]: https://i.creativecommons.org/l/by-nd/4.0/88x31.png "Creative Commons License"
+[4]: https://creativecommons.org/licenses/by-nd/4.0/
+
 The `VK_LAYER_LUNARG_unique_objects` is a validation-supporting utility layer which enables consistent and coherent validation in addition to proper operation on systems which return non-unique object handles.  This layer aliases all non-dispatchable Vulkan objects with a unique identifier at object-creation time. The aliased handles are used during validation to ensure that duplicate object handles are correctly managed and tracked by the validation layers.
 
-Note:  
+**Note**:
 
 * For optimal efficiency, this layer MUST be last in the chain (closest to the display driver).
 * If you are developing Vulkan extensions which include new APIs taking one or more Vulkan dispatchable objects as parameters, you may find it necessary to disable the unique objects layer in order use the validation layers. The best way to do this is to explicitly load the layers in the optimal order specified earlier but without this layer. This should result in a minimal decrease in functionality but still allow you to benefit from using the validation layers.
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 5fd5b44..eb3dbe3 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -1,6 +1,6 @@
 # ~~~
-# Copyright (c) 2014-2018 Valve Corporation
-# Copyright (c) 2014-2018 LunarG, Inc.
+# Copyright (c) 2014-2019 Valve Corporation
+# Copyright (c) 2014-2019 LunarG, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -85,33 +85,35 @@
 
 set(TARGET_NAMES
     VkLayer_core_validation
-    VkLayer_object_tracker
+    VkLayer_object_lifetimes
     VkLayer_unique_objects
-    VkLayer_parameter_validation
+    VkLayer_stateless_validation
     VkLayer_standard_validation
-    VkLayer_threading)
+    VkLayer_thread_safety)
 
-# Install the layer json files
-if(WIN32)
-    if(CMAKE_GENERATOR MATCHES "^Visual Studio.*")
+if(BUILD_LAYERS)
+    # Install the layer json files
+    if(WIN32)
+        if(CMAKE_GENERATOR MATCHES "^Visual Studio.*")
+            foreach(TARGET_NAME ${TARGET_NAMES})
+                install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${TARGET_NAME}.json DESTINATION ${CMAKE_INSTALL_LIBDIR})
+            endforeach()
+        else()
+            foreach(TARGET_NAME ${TARGET_NAMES})
+                install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.json DESTINATION ${CMAKE_INSTALL_LIBDIR})
+            endforeach()
+        endif()
+    elseif(UNIX) # UNIX includes APPLE
         foreach(TARGET_NAME ${TARGET_NAMES})
-            install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${TARGET_NAME}.json DESTINATION ${CMAKE_INSTALL_LIBDIR})
-        endforeach()
-    else()
-        foreach(TARGET_NAME ${TARGET_NAMES})
-            install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.json DESTINATION ${CMAKE_INSTALL_LIBDIR})
+            install(FILES ${CMAKE_CURRENT_BINARY_DIR}/staging-json/${TARGET_NAME}.json
+                    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/vulkan/explicit_layer.d)
         endforeach()
     endif()
-elseif(UNIX) # UNIX includes APPLE
-    foreach(TARGET_NAME ${TARGET_NAMES})
-        install(FILES ${CMAKE_CURRENT_BINARY_DIR}/staging-json/${TARGET_NAME}.json
-                DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/vulkan/explicit_layer.d)
-    endforeach()
 endif()
 
 # System-specific macros to create a library target.
 if(WIN32)
-    macro(AddVkLayer target)
+    macro(AddVkLayer target LAYER_COMPILE_DEFINITIONS)
         file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/VkLayer_${target}.def DEF_FILE)
         add_custom_target(copy-${target}-def-file ALL
                           COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEF_FILE} VkLayer_${target}.def
@@ -119,15 +121,17 @@
         set_target_properties(copy-${target}-def-file PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
 
         add_library(VkLayer_${target} SHARED ${ARGN} VkLayer_${target}.def)
+        target_compile_definitions(VkLayer_${target} PUBLIC ${LAYER_COMPILE_DEFINITIONS})
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VulkanVL_generate_chassis_files VkLayer_utils)
         install(TARGETS VkLayer_${target} DESTINATION ${CMAKE_INSTALL_LIBDIR})
     endmacro()
 elseif(APPLE)
-    macro(AddVkLayer target)
+    macro(AddVkLayer target LAYER_COMPILE_DEFINITIONS)
         add_library(VkLayer_${target} SHARED ${ARGN})
+        target_compile_definitions(VkLayer_${target} PUBLIC ${LAYER_COMPILE_DEFINITIONS})
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VulkanVL_generate_chassis_files VkLayer_utils)
         set_target_properties(VkLayer_${target}
                               PROPERTIES LINK_FLAGS
                                          "-Wl"
@@ -136,10 +140,11 @@
         install(TARGETS VkLayer_${target} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
     endmacro()
 else(UNIX AND NOT APPLE) # i.e.: Linux
-    macro(AddVkLayer target)
+    macro(AddVkLayer target LAYER_COMPILE_DEFINITIONS)
         add_library(VkLayer_${target} SHARED ${ARGN})
+        target_compile_definitions(VkLayer_${target} PUBLIC ${LAYER_COMPILE_DEFINITIONS})
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VulkanVL_generate_chassis_files VkLayer_utils)
         set_target_properties(VkLayer_${target} PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic,--exclude-libs,ALL")
         install(TARGETS VkLayer_${target} DESTINATION ${CMAKE_INSTALL_LIBDIR})
     endmacro()
@@ -151,13 +156,7 @@
     # Applies to all configurations
     add_definitions(-D_CRT_SECURE_NO_WARNINGS)
     # Avoid: fatal error C1128: number of sections exceeded object file format limit: compile with /bigobj
-    set_source_files_properties(core_validation.cpp
-                                threading.cpp
-                                parameter_validation_utils.cpp
-                                unique_objects.cpp
-                                PROPERTIES
-                                COMPILE_FLAGS
-                                "/bigobj")
+    add_compile_options("/bigobj")
     # Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015. The changed behavior is
     # that constructor initializers are now fixed to clear the struct members.
     add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,19>>:/wd4351>")
@@ -171,74 +170,90 @@
     set_source_files_properties(parameter_validation.cpp PROPERTIES COMPILE_FLAGS "-Wno-unused-const-variable")
 endif()
 
-GenerateFromVkXml(threading_generator.py thread_check.h)
+GenerateFromVkXml(thread_safety_generator.py thread_safety.h)
+GenerateFromVkXml(thread_safety_generator.py thread_safety.cpp)
 GenerateFromVkXml(parameter_validation_generator.py parameter_validation.cpp)
-GenerateFromVkXml(unique_objects_generator.py unique_objects_wrappers.h)
+GenerateFromVkXml(parameter_validation_generator.py parameter_validation.h)
 GenerateFromVkXml(dispatch_table_helper_generator.py vk_dispatch_table_helper.h)
 GenerateFromVkXml(object_tracker_generator.py object_tracker.cpp)
+GenerateFromVkXml(object_tracker_generator.py object_tracker.h)
+GenerateFromVkXml(layer_chassis_generator.py chassis.cpp)
+GenerateFromVkXml(layer_chassis_generator.py chassis.h)
+GenerateFromVkXml(layer_chassis_dispatch_generator.py layer_chassis_dispatch.h)
+GenerateFromVkXml(layer_chassis_dispatch_generator.py layer_chassis_dispatch.cpp)
 
+# This target causes the chassis source files to be generated.
+add_custom_target(VulkanVL_generate_chassis_files
+                  DEPENDS chassis.cpp
+                          chassis.h
+                          layer_chassis_dispatch.h
+                          layer_chassis_dispatch.cpp)
+set_target_properties(VulkanVL_generate_chassis_files PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
+
+# Inter-layer dependencies are temporarily necessary to serialize layer builds which avoids contention for common generated files
 if(BUILD_LAYERS)
-    AddVkLayer(core_validation core_validation.cpp convert_to_renderpass2.cpp descriptor_sets.cpp buffer_validation.cpp shader_validation.cpp xxhash.c)
-    AddVkLayer(object_tracker object_tracker.cpp object_tracker_utils.cpp)
-    AddVkLayer(threading threading.cpp thread_check.h)
-    AddVkLayer(unique_objects unique_objects.cpp unique_objects_wrappers.h)
-    AddVkLayer(parameter_validation
-               parameter_validation.cpp
-               parameter_validation_utils.cpp
-               parameter_validation.h
-               vk_validation_error_messages.h)
+    AddVkLayer(core_validation "BUILD_CORE_VALIDATION" chassis.cpp layer_chassis_dispatch.cpp core_validation.cpp convert_to_renderpass2.cpp descriptor_sets.cpp buffer_validation.cpp shader_validation.cpp gpu_validation.cpp xxhash.c)
+    add_dependencies(VkLayer_core_validation VulkanVL_generate_chassis_files)
+    AddVkLayer(object_lifetimes "BUILD_OBJECT_TRACKER" object_tracker.cpp object_tracker.h object_tracker_utils.cpp chassis.cpp layer_chassis_dispatch.cpp)
+    add_dependencies(VkLayer_object_lifetimes VkLayer_core_validation)
+    AddVkLayer(thread_safety "BUILD_THREAD_SAFETY" thread_safety.cpp thread_safety.h chassis.cpp layer_chassis_dispatch.cpp)
+    add_dependencies(VkLayer_thread_safety VkLayer_object_lifetimes)
+    AddVkLayer(unique_objects "LAYER_CHASSIS_CAN_WRAP_HANDLES" chassis.cpp layer_chassis_dispatch.cpp)
+    add_dependencies(VkLayer_unique_objects VkLayer_thread_safety)
+    AddVkLayer(stateless_validation "BUILD_PARAMETER_VALIDATION" parameter_validation.cpp parameter_validation.h parameter_validation_utils.cpp chassis.cpp layer_chassis_dispatch.cpp)
+    add_dependencies(VkLayer_stateless_validation VkLayer_unique_objects)
 
     # Core validation has additional dependencies
     target_include_directories(VkLayer_core_validation PRIVATE ${GLSLANG_SPIRV_INCLUDE_DIR})
     target_include_directories(VkLayer_core_validation PRIVATE ${SPIRV_TOOLS_INCLUDE_DIR})
     target_link_libraries(VkLayer_core_validation PRIVATE ${SPIRV_TOOLS_LIBRARIES})
     add_dependencies(VkLayer_core_validation spirv_tools_revision_file)
-endif()
 
-# The output file needs Unix "/" separators or Windows "\" separators On top of that, Windows separators actually need to be doubled
-# because the json format uses backslash escapes
-file(TO_NATIVE_PATH "./" RELATIVE_PATH_PREFIX)
-string(REPLACE "\\"
-               "\\\\"
-               RELATIVE_PATH_PREFIX
-               "${RELATIVE_PATH_PREFIX}")
+    # The output file needs Unix "/" separators or Windows "\" separators On top of that, Windows separators actually need to be doubled
+    # because the json format uses backslash escapes
+    file(TO_NATIVE_PATH "./" RELATIVE_PATH_PREFIX)
+    string(REPLACE "\\"
+                   "\\\\"
+                   RELATIVE_PATH_PREFIX
+                   "${RELATIVE_PATH_PREFIX}")
 
-# Run each .json.in file through the generator We need to create the generator.cmake script so that the generator can be run at
-# compile time, instead of configure time Running at compile time lets us use cmake generator expressions (TARGET_FILE_NAME and
-# TARGET_FILE_DIR, specifically)
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake" "configure_file(\"\${INPUT_FILE}\" \"\${OUTPUT_FILE}\")")
-foreach(TARGET_NAME ${TARGET_NAMES})
-    set(CONFIG_DEFINES -DINPUT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/json/${TARGET_NAME}.json.in" -DVK_VERSION=1.1.${vk_header_version})
-    # If this json file is not a metalayer, get the needed properties from that target
-    if(TARGET ${TARGET_NAME})
-        set(CONFIG_DEFINES
-            ${CONFIG_DEFINES}
-            -DOUTPUT_FILE="$<TARGET_FILE_DIR:${TARGET_NAME}>/${TARGET_NAME}.json"
-            -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${TARGET_NAME}>")
-        # If this json file is a metalayer, make the output path match core validation, and there is no layer binary file
-    else()
-        set(CONFIG_DEFINES ${CONFIG_DEFINES} -DOUTPUT_FILE="$<TARGET_FILE_DIR:VkLayer_core_validation>/${TARGET_NAME}.json")
-    endif()
-    add_custom_target(${TARGET_NAME}-json ALL
-                      COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
-    if(CMAKE_GENERATOR MATCHES "^Visual Studio.*")
-        set_target_properties(${TARGET_NAME}-json PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
-    endif()
-endforeach()
-
-# For UNIX-based systems, `library_path` should not contain a relative path (indicated by "./") before installing to system
-# directories, so we do not include it in the staging-json files which are used for installation
-if(UNIX)
+    # Run each .json.in file through the generator We need to create the generator.cmake script so that the generator can be run at
+    # compile time, instead of configure time Running at compile time lets us use cmake generator expressions (TARGET_FILE_NAME and
+    # TARGET_FILE_DIR, specifically)
+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake" "configure_file(\"\${INPUT_FILE}\" \"\${OUTPUT_FILE}\")")
     foreach(TARGET_NAME ${TARGET_NAMES})
-        set(INSTALL_DEFINES
-            -DINPUT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/json/${TARGET_NAME}.json.in"
-            -DOUTPUT_FILE="${CMAKE_CURRENT_BINARY_DIR}/staging-json/${TARGET_NAME}.json"
-            -DVK_VERSION=1.1.${vk_header_version})
+        set(CONFIG_DEFINES -DINPUT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/json/${TARGET_NAME}.json.in" -DVK_VERSION=1.1.${vk_header_version})
         # If this json file is not a metalayer, get the needed properties from that target
         if(TARGET ${TARGET_NAME})
-            set(INSTALL_DEFINES ${INSTALL_DEFINES} -DRELATIVE_LAYER_BINARY="$<TARGET_FILE_NAME:${TARGET_NAME}>")
+            set(CONFIG_DEFINES
+                ${CONFIG_DEFINES}
+                -DOUTPUT_FILE="$<TARGET_FILE_DIR:${TARGET_NAME}>/${TARGET_NAME}.json"
+                -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${TARGET_NAME}>")
+            # If this json file is a metalayer, make the output path match core validation, and there is no layer binary file
+        else()
+            set(CONFIG_DEFINES ${CONFIG_DEFINES} -DOUTPUT_FILE="$<TARGET_FILE_DIR:VkLayer_core_validation>/${TARGET_NAME}.json")
         endif()
-        add_custom_target(${TARGET_NAME}-staging-json ALL
-                          COMMAND ${CMAKE_COMMAND} ${INSTALL_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
+        add_custom_target(${TARGET_NAME}-json ALL
+                          COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
+        if(CMAKE_GENERATOR MATCHES "^Visual Studio.*")
+            set_target_properties(${TARGET_NAME}-json PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
+        endif()
     endforeach()
+
+    # For UNIX-based systems, `library_path` should not contain a relative path (indicated by "./") before installing to system
+    # directories, so we do not include it in the staging-json files which are used for installation
+    if(UNIX)
+        foreach(TARGET_NAME ${TARGET_NAMES})
+            set(INSTALL_DEFINES
+                -DINPUT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/json/${TARGET_NAME}.json.in"
+                -DOUTPUT_FILE="${CMAKE_CURRENT_BINARY_DIR}/staging-json/${TARGET_NAME}.json"
+                -DVK_VERSION=1.1.${vk_header_version})
+            # If this json file is not a metalayer, get the needed properties from that target
+            if(TARGET ${TARGET_NAME})
+                set(INSTALL_DEFINES ${INSTALL_DEFINES} -DRELATIVE_LAYER_BINARY="$<TARGET_FILE_NAME:${TARGET_NAME}>")
+            endif()
+            add_custom_target(${TARGET_NAME}-staging-json ALL
+                              COMMAND ${CMAKE_COMMAND} ${INSTALL_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
+        endforeach()
+    endif()
 endif()
diff --git a/layers/README.md b/layers/README.md
index bc6728e..eb9ab02 100644
--- a/layers/README.md
+++ b/layers/README.md
@@ -49,13 +49,13 @@
 layers/core\_validation.cpp (name=`VK_LAYER_LUNARG_core_validation`) - The core\_validation layer does the bulk of the API validation that requires storing state. Some of the state it tracks includes the Descriptor Set, Pipeline State, Shaders, and dynamic state, and memory objects and bindings. It performs some point validation as states are created and used, and further validation Draw call and QueueSubmit time. Of primary interest is making sure that the resources bound to Descriptor Sets correctly align with the layout specified for the Set. Also, all of the image and buffer layouts are validated to make sure explicit layout transitions are properly managed. Related to memory, core\_validation includes tracking object bindings, memory hazards, and memory object lifetimes. It also validates several other hazard-related issues related to command buffers, fences, and memory mapping. Additionally core\_validation include shader validation (formerly separate shader\_checker layer) that inspects the SPIR-V shader images and fixed function pipeline stages at PSO creation time. It flags errors when inconsistencies are found across interfaces between shader stages. The exact behavior of the checks depends on the pair of pipeline stages involved. If a Dbg callback function is registered, this layer will use callback function(s) for reporting, otherwise uses stdout.  This layer also validates correct usage of image- and buffer-related APIs, including image and buffer parameters, formats, and correct use.
 
 ### Check parameters
-layers/parameter_validation.cpp (name=`VK_LAYER_LUNARG_parameter_validation`) - Check the input parameters to API calls for validity. If a Dbg callback function is registered, this layer will use callback function(s) for reporting, otherwise uses stdout.
+(build_dir)/layers/parameter_validation.cpp (name=`VK_LAYER_LUNARG_parameter_validation`) - Check the input parameters to API calls for validity. If a Dbg callback function is registered, this layer will use callback function(s) for reporting, otherwise uses stdout.
 
 ### Check threading
-layers/threading.cpp (name=`VK_LAYER_GOOGLE_threading`) - Check multithreading of API calls for validity. Currently this checks that only one thread at a time uses an object in free-threaded API calls. If a Dbg callback function is registered, this layer will use callback function(s) for reporting, otherwise uses stdout.
+(build_dir)/layers/threading.cpp (name=`VK_LAYER_GOOGLE_threading`) - Check multithreading of API calls for validity. Currently this checks that only one thread at a time uses an object in free-threaded API calls. If a Dbg callback function is registered, this layer will use callback function(s) for reporting, otherwise uses stdout.
 
 ### Unique Objects
-(build dir)/layers/unique_objects.cpp (name=`VK_LAYER_GOOGLE_unique_objects`) - The Vulkan specification allows objects that have non-unique handles. This makes tracking object lifetimes difficult in that it is unclear which object is being referenced on deletion. The unique_objects layer was created to address this problem. If loaded in the correct position (last, which is closest to the display driver) it will alias all objects with a unique object representation, allowing proper object lifetime tracking. This layer does no validation on its own and may not be required for the proper operation of all layers or all platforms. One sign that it is needed is the appearance of errors emitted from the object_tracker layer indicating the use of previously destroyed objects.
+(build dir)/layers/layer_chassis_dispatch.cpp (name=`VK_LAYER_GOOGLE_unique_objects`) - The Vulkan specification allows objects that have non-unique handles. This makes tracking object lifetimes difficult in that it is unclear which object is being referenced on deletion. The unique_objects layer was created to address this problem. If loaded in the correct position (last, which is closest to the display driver) it will alias all objects with a unique object representation, allowing proper object lifetime tracking. This layer does no validation on its own and may not be required for the proper operation of all layers or all platforms. One sign that it is needed is the appearance of errors emitted from the object_tracker layer indicating the use of previously destroyed objects.
 
 ## Using Layers
 
diff --git a/layers/VkLayer_image.def b/layers/VkLayer_image.def
deleted file mode 100644
index ff442df..0000000
--- a/layers/VkLayer_image.def
+++ /dev/null
@@ -1,29 +0,0 @@
-
-;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Copyright (c) 2015-2016 The Khronos Group Inc.
-; Copyright (c) 2015-2016 Valve Corporation
-; Copyright (c) 2015-2016 LunarG, Inc.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;     http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-;  Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
-;
-;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-LIBRARY VkLayer_image
-EXPORTS
-vkGetInstanceProcAddr
-vkGetDeviceProcAddr
-vkEnumerateInstanceLayerProperties
-vkEnumerateInstanceExtensionProperties
diff --git a/layers/VkLayer_threading.def b/layers/VkLayer_object_lifetimes.def
similarity index 91%
rename from layers/VkLayer_threading.def
rename to layers/VkLayer_object_lifetimes.def
index c285020..9b170e4 100644
--- a/layers/VkLayer_threading.def
+++ b/layers/VkLayer_object_lifetimes.def
@@ -17,11 +17,11 @@
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
 ;
-;  Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+;  Author: Mark Lobodzinski <mark@lunarg.com>
 ;
 ;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-LIBRARY VkLayer_threading
+LIBRARY VkLayer_object_lifetimes
 EXPORTS
 vkGetInstanceProcAddr
 vkGetDeviceProcAddr
diff --git a/layers/VkLayer_object_tracker.def b/layers/VkLayer_object_tracker.def
deleted file mode 100644
index 0ce5f47..0000000
--- a/layers/VkLayer_object_tracker.def
+++ /dev/null
@@ -1,30 +0,0 @@
-
-;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Copyright (c) 2015-2016 The Khronos Group Inc.
-; Copyright (c) 2015-2016 Valve Corporation
-; Copyright (c) 2015-2016 LunarG, Inc.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;     http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-;  Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
-;
-;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-LIBRARY VkLayer_object_tracker
-EXPORTS
-vkGetInstanceProcAddr
-vkGetDeviceProcAddr
-vkEnumerateInstanceLayerProperties
-vkEnumerateInstanceExtensionProperties
-vkNegotiateLoaderLayerInterfaceVersion
diff --git a/layers/VkLayer_parameter_validation.def b/layers/VkLayer_stateless_validation.def
similarity index 96%
copy from layers/VkLayer_parameter_validation.def
copy to layers/VkLayer_stateless_validation.def
index ccbef25..5a427e9 100644
--- a/layers/VkLayer_parameter_validation.def
+++ b/layers/VkLayer_stateless_validation.def
@@ -21,7 +21,7 @@
 ;
 ;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-LIBRARY VkLayer_parameter_validation
+LIBRARY VkLayer_stateless_validation
 EXPORTS
 vkGetInstanceProcAddr
 vkGetDeviceProcAddr
diff --git a/layers/VkLayer_swapchain.def b/layers/VkLayer_swapchain.def
deleted file mode 100644
index c7431bb..0000000
--- a/layers/VkLayer_swapchain.def
+++ /dev/null
@@ -1,29 +0,0 @@
-
-;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Copyright (c) 2015-2016 The Khronos Group Inc.
-; Copyright (c) 2015-2016 Valve Corporation
-; Copyright (c) 2015-2016 LunarG, Inc.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-;
-;     http://www.apache.org/licenses/LICENSE-2.0
-;
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-;  Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
-;
-;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-LIBRARY VkLayer_swapchain
-EXPORTS
-vkGetInstanceProcAddr
-vkGetDeviceProcAddr
-vkEnumerateInstanceLayerProperties
-vkEnumerateInstanceExtensionProperties
diff --git a/layers/VkLayer_parameter_validation.def b/layers/VkLayer_thread_safety.def
similarity index 96%
rename from layers/VkLayer_parameter_validation.def
rename to layers/VkLayer_thread_safety.def
index ccbef25..54323cf 100644
--- a/layers/VkLayer_parameter_validation.def
+++ b/layers/VkLayer_thread_safety.def
@@ -21,7 +21,7 @@
 ;
 ;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-LIBRARY VkLayer_parameter_validation
+LIBRARY VkLayer_thread_safety
 EXPORTS
 vkGetInstanceProcAddr
 vkGetDeviceProcAddr
diff --git a/layers/android_ndk_types.h b/layers/android_ndk_types.h
new file mode 100644
index 0000000..515f128
--- /dev/null
+++ b/layers/android_ndk_types.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2018-2019 The Khronos Group Inc.
+ * Copyright (c) 2018-2019 Valve Corporation
+ * Copyright (c) 2018-2019 LunarG, Inc.
+ * Copyright (C) 2018-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Dave Houlton <daveh@lunarg.com>
+ */
+
+#ifndef ANDROID_NDK_TYPES_H_
+#define ANDROID_NDK_TYPES_H_
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
+// All eums referenced by VK_ANDROID_external_memory_android_hardware_buffer are present in
+// the platform-28 (Android P) versions of the header files.  A partial set exists in the
+// platform-26 (O) headers, where hardware_buffer.h first appears in the NDK.
+//
+// Building Vulkan validation with NDK header files prior to platform-26 is not supported.
+//
+// Decoder ring for Android compile symbols found here: https://github.com/android-ndk/ndk/issues/407
+
+#ifdef __ANDROID__  // Compiling for Android
+#include <android/api-level.h>
+#include <android/hardware_buffer.h>  // First appearance in Android O (platform-26)
+
+// If NDK is O (platform-26 or -27), supplement the missing enums with pre-processor defined literals
+// If Android P or later, then all required enums are already defined
+#if defined(__ANDROID_API_O__) && !defined(__ANDROID_API_P__)
+// Formats
+#define AHARDWAREBUFFER_FORMAT_D16_UNORM 0x30
+#define AHARDWAREBUFFER_FORMAT_D24_UNORM 0x31
+#define AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT 0x32
+#define AHARDWAREBUFFER_FORMAT_D32_FLOAT 0x33
+#define AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT 0x34
+#define AHARDWAREBUFFER_FORMAT_S8_UINT 0x35
+// Usage bits
+#define AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP 0x2000000
+#define AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE 0x4000000
+#endif  // __ANDROID_API_O__ && !_P__
+
+#else  // Not __ANDROID__, but VK_USE_PLATFORM_ANDROID_KHR
+// This combination should not be seen in the wild, but can be used to allow testing
+// of the AHB extension validation on other platforms using MockICD
+//
+// Define the minimal set of NDK enums and structs needed to compile
+// VK_ANDROID_external_memory_android_hardware_buffer validation without an NDK present
+struct AHardwareBuffer {};
+
+// Enumerations of format and usage flags for Android opaque external memory blobs
+typedef enum AHardwareBufferFormat {
+    AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
+    AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
+    AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
+    AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
+    AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT = 0x16,
+    AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b,
+    AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30,
+    AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31,
+    AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32,
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33,
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34,
+    AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35,
+    AHARDWAREBUFFER_FORMAT_BLOB = 0x21
+} AHardwareBufferFormat;
+
+typedef enum AHardwareBufferUsage {
+    AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 0x100,
+    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 0x200,
+    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 0x2000000,
+    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 0x4000000,
+    AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 0x4000,
+    AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 0x1000000
+} AHardwareBufferUsage;
+
+typedef struct AHardwareBuffer_Desc {
+    uint32_t format;  //	   One of AHARDWAREBUFFER_FORMAT_*.
+    uint32_t height;  //	   Height in pixels.
+    uint32_t layers;  //	   Number of images in an image array.
+    uint32_t rfu0;    //	   Initialize to zero, reserved for future use.
+    uint64_t rfu1;    //	   Initialize to zero, reserved for future use.
+    uint32_t stride;  //	   Row stride in pixels, ignored for AHardwareBuffer_allocate()
+    uint64_t usage;   //	   Combination of AHARDWAREBUFFER_USAGE_*.
+    uint32_t width;   //	   Width in pixels.
+} AHardwareBuffer_Desc;
+
+// Minimal NDK fxn stubs to allow testing on ndk-less platform
+static inline int AHardwareBuffer_allocate(const AHardwareBuffer_Desc *ahbDesc, AHardwareBuffer **buffer) {
+    size_t size = ahbDesc->height * ahbDesc->width * 8;  // Alloc for largest (64 bpp) format
+    if (size < sizeof(AHardwareBuffer_Desc)) size = sizeof(AHardwareBuffer_Desc);
+    *buffer = (AHardwareBuffer *)malloc(size);
+    memcpy((void *)(*buffer), (void *)ahbDesc, sizeof(AHardwareBuffer_Desc));
+    return 0;
+}
+
+static inline void AHardwareBuffer_release(AHardwareBuffer *buffer) {
+    if (buffer) free(buffer);
+}
+
+static inline void AHardwareBuffer_describe(const AHardwareBuffer *buffer, AHardwareBuffer_Desc *outDesc) {
+    if (buffer && outDesc) {
+        memcpy((void *)outDesc, (void *)buffer, sizeof(AHardwareBuffer_Desc));
+    }
+    return;
+}
+
+#endif  // __ANDROID__
+
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+#endif  // ANDROID_NDK_TYPES_H_
diff --git a/layers/buffer_validation.cpp b/layers/buffer_validation.cpp
index bb7edf7..ccf377e 100644
--- a/layers/buffer_validation.cpp
+++ b/layers/buffer_validation.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,11 +17,14 @@
  *
  * Author: Mark Lobodzinski <mark@lunarg.com>
  * Author: Dave Houlton <daveh@lunarg.com>
+ * Shannon McPherson <shannon@lunarg.com>
  */
 
 // Allow use of STL min and max functions in Windows
 #define NOMINMAX
 
+#include <cmath>
+#include <set>
 #include <sstream>
 #include <string>
 
@@ -31,9 +34,23 @@
 #include "vk_layer_logging.h"
 #include "vk_typemap_helper.h"
 
+#include "chassis.h"
+#include "core_validation.h"
+#include "shader_validation.h"
+#include "descriptor_sets.h"
 #include "buffer_validation.h"
 
-void SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
+uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
+    // uint cast applies floor()
+    return 1u + (uint32_t)log2(std::max({height, width, depth}));
+}
+
+uint32_t FullMipChainLevels(VkExtent3D extent) { return FullMipChainLevels(extent.height, extent.width, extent.depth); }
+
+uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
+
+void CoreChecks::SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
+                           const VkImageLayout &layout) {
     auto it = pCB->imageLayoutMap.find(imgpair);
     if (it != pCB->imageLayoutMap.end()) {
         it->second.layout = layout;
@@ -46,14 +63,16 @@
         SetLayout(device_data, pCB, imgpair, {node.initialLayout, layout});
     }
 }
+
 template <class OBJECT, class LAYOUT>
-void SetLayout(layer_data *device_data, OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
+void CoreChecks::SetLayout(layer_data *device_data, OBJECT *pObject, VkImage image, VkImageSubresource range,
+                           const LAYOUT &layout) {
     ImageSubresourcePair imgpair = {image, true, range};
     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
-    if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+    if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
@@ -61,8 +80,8 @@
 }
 
 template <class OBJECT, class LAYOUT>
-void SetLayout(layer_data *device_data, OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout,
-               VkImageAspectFlags aspectMask) {
+void CoreChecks::SetLayout(layer_data *device_data, OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout,
+                           VkImageAspectFlags aspectMask) {
     if (imgpair.subresource.aspectMask & aspectMask) {
         imgpair.subresource.aspectMask = aspectMask;
         SetLayout(device_data, pObject, imgpair, layout);
@@ -70,8 +89,8 @@
 }
 
 // Set the layout in supplied map
-void SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap, ImageSubresourcePair imgpair,
-               VkImageLayout layout) {
+void CoreChecks::SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
+                           ImageSubresourcePair imgpair, VkImageLayout layout) {
     auto it = imageLayoutMap.find(imgpair);
     if (it != imageLayoutMap.end()) {
         it->second.layout = layout;  // Update
@@ -80,10 +99,8 @@
     }
 }
 
-bool FindLayoutVerifyNode(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, ImageSubresourcePair imgpair,
-                          IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
-
+bool CoreChecks::FindLayoutVerifyNode(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, ImageSubresourcePair imgpair,
+                                      IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
     if (!(imgpair.subresource.aspectMask & aspectMask)) {
         return false;
     }
@@ -96,39 +113,38 @@
     if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
                 kVUID_Core_DrawState_InvalidLayout,
-                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
-                HandleToUint64(imgpair.image), oldAspectMask, string_VkImageLayout(node.layout),
+                "Cannot query for VkImage %s layout when combined aspect mask %d has multiple layout types: %s and %s",
+                report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.layout),
                 string_VkImageLayout(imgsubIt->second.layout));
     }
     if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
                 kVUID_Core_DrawState_InvalidLayout,
-                "Cannot query for VkImage 0x%" PRIx64
+                "Cannot query for VkImage %s"
                 " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
-                HandleToUint64(imgpair.image), oldAspectMask, string_VkImageLayout(node.initialLayout),
+                report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.initialLayout),
                 string_VkImageLayout(imgsubIt->second.initialLayout));
     }
     node = imgsubIt->second;
     return true;
 }
 
-bool FindLayoutVerifyLayout(layer_data const *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
-                            const VkImageAspectFlags aspectMask) {
+bool CoreChecks::FindLayoutVerifyLayout(layer_data const *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
+                                        const VkImageAspectFlags aspectMask) {
     if (!(imgpair.subresource.aspectMask & aspectMask)) {
         return false;
     }
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
     VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
     imgpair.subresource.aspectMask = aspectMask;
-    auto imgsubIt = (*core_validation::GetImageLayoutMap(device_data)).find(imgpair);
-    if (imgsubIt == (*core_validation::GetImageLayoutMap(device_data)).end()) {
+    auto imgsubIt = (*GetImageLayoutMap()).find(imgpair);
+    if (imgsubIt == (*GetImageLayoutMap()).end()) {
         return false;
     }
     if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
                 kVUID_Core_DrawState_InvalidLayout,
-                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
-                HandleToUint64(imgpair.image), oldAspectMask, string_VkImageLayout(layout),
+                "Cannot query for VkImage %s layout when combined aspect mask %d has multiple layout types: %s and %s",
+                report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(layout),
                 string_VkImageLayout(imgsubIt->second.layout));
     }
     layout = imgsubIt->second.layout;
@@ -136,15 +152,15 @@
 }
 
 // Find layout(s) on the command buffer level
-bool FindCmdBufLayout(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, VkImage image, VkImageSubresource range,
-                      IMAGE_CMD_BUF_LAYOUT_NODE &node) {
+bool CoreChecks::FindCmdBufLayout(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, VkImage image, VkImageSubresource range,
+                                  IMAGE_CMD_BUF_LAYOUT_NODE &node) {
     ImageSubresourcePair imgpair = {image, true, range};
     node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
-    if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+    if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
@@ -160,30 +176,30 @@
 }
 
 // Find layout(s) on the global level
-bool FindGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
+bool CoreChecks::FindGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
     layout = VK_IMAGE_LAYOUT_MAX_ENUM;
     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
-    if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+    if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     }
     if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
         imgpair = {imgpair.image, false, VkImageSubresource()};
-        auto imgsubIt = (*core_validation::GetImageLayoutMap(device_data)).find(imgpair);
-        if (imgsubIt == (*core_validation::GetImageLayoutMap(device_data)).end()) return false;
+        auto imgsubIt = (*GetImageLayoutMap()).find(imgpair);
+        if (imgsubIt == (*GetImageLayoutMap()).end()) return false;
         layout = imgsubIt->second.layout;
     }
     return true;
 }
 
-bool FindLayouts(layer_data *device_data, VkImage image, std::vector<VkImageLayout> &layouts) {
-    auto sub_data = (*core_validation::GetImageSubresourceMap(device_data)).find(image);
-    if (sub_data == (*core_validation::GetImageSubresourceMap(device_data)).end()) return false;
-    auto image_state = GetImageState(device_data, image);
+bool CoreChecks::FindLayouts(layer_data *device_data, VkImage image, std::vector<VkImageLayout> &layouts) {
+    auto sub_data = (*GetImageSubresourceMap()).find(image);
+    if (sub_data == (*GetImageSubresourceMap()).end()) return false;
+    auto image_state = GetImageState(image);
     if (!image_state) return false;
     bool ignoreGlobal = false;
     // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
@@ -192,15 +208,16 @@
     }
     for (auto imgsubpair : sub_data->second) {
         if (ignoreGlobal && !imgsubpair.hasSubresource) continue;
-        auto img_data = (*core_validation::GetImageLayoutMap(device_data)).find(imgsubpair);
-        if (img_data != (*core_validation::GetImageLayoutMap(device_data)).end()) {
+        auto img_data = (*GetImageLayoutMap()).find(imgsubpair);
+        if (img_data != (*GetImageLayoutMap()).end()) {
             layouts.push_back(img_data->second.layout);
         }
     }
     return true;
 }
-bool FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap, ImageSubresourcePair imgpair,
-                VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
+
+bool CoreChecks::FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
+                            ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
     if (!(imgpair.subresource.aspectMask & aspectMask)) {
         return false;
     }
@@ -214,14 +231,15 @@
 }
 
 // find layout in supplied map
-bool FindLayout(layer_data *device_data, const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
-                ImageSubresourcePair imgpair, VkImageLayout &layout) {
+bool CoreChecks::FindLayout(layer_data *device_data,
+                            const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
+                            ImageSubresourcePair imgpair, VkImageLayout &layout) {
     layout = VK_IMAGE_LAYOUT_MAX_ENUM;
     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
-    if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+    if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
@@ -237,16 +255,16 @@
 }
 
 // Set the layout on the global level
-void SetGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
+void CoreChecks::SetGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
     VkImage &image = imgpair.image;
-    auto &lmap = (*core_validation::GetImageLayoutMap(device_data));
+    auto &lmap = (*GetImageLayoutMap());
     auto data = lmap.find(imgpair);
     if (data != lmap.end()) {
         data->second.layout = layout;  // Update
     } else {
         lmap[imgpair].layout = layout;  // Insert
     }
-    auto &image_subresources = (*core_validation::GetImageSubresourceMap(device_data))[image];
+    auto &image_subresources = (*GetImageSubresourceMap())[image];
     auto subresource = std::find(image_subresources.begin(), image_subresources.end(), imgpair);
     if (subresource == image_subresources.end()) {
         image_subresources.push_back(imgpair);
@@ -254,7 +272,8 @@
 }
 
 // Set the layout on the cmdbuf level
-void SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
+void CoreChecks::SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
+                           const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
     auto it = pCB->imageLayoutMap.find(imgpair);
     if (it != pCB->imageLayoutMap.end()) {
         it->second = node;  // Update
@@ -263,8 +282,8 @@
     }
 }
 // Set image layout for given VkImageSubresourceRange struct
-void SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
-                    VkImageSubresourceRange image_subresource_range, const VkImageLayout &layout) {
+void CoreChecks::SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
+                                VkImageSubresourceRange image_subresource_range, const VkImageLayout &layout) {
     assert(image_state);
     cb_node->image_layout_change_count++;  // Change the version of this data to force revalidation
     for (uint32_t level_index = 0; level_index < image_subresource_range.levelCount; ++level_index) {
@@ -279,13 +298,25 @@
                     sub.aspectMask |= (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
                 }
             }
+            // For multiplane images, IMAGE_ASPECT_COLOR is an alias for all of the plane bits
+            if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
+                if (FormatIsMultiplane(image_state->createInfo.format)) {
+                    if (sub.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
+                        sub.aspectMask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
+                        sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR;
+                        if (FormatPlaneCount(image_state->createInfo.format) > 2) {
+                            sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
+                        }
+                    }
+                }
+            }
             SetLayout(device_data, cb_node, image_state->image, sub, layout);
         }
     }
 }
 // Set image layout for given VkImageSubresourceLayers struct
-void SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
-                    VkImageSubresourceLayers image_subresource_layers, const VkImageLayout &layout) {
+void CoreChecks::SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
+                                VkImageSubresourceLayers image_subresource_layers, const VkImageLayout &layout) {
     // Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
     VkImageSubresourceRange image_subresource_range;
     image_subresource_range.aspectMask = image_subresource_layers.aspectMask;
@@ -297,11 +328,11 @@
 }
 
 // Set image layout for all slices of an image view
-void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state,
-                        const VkImageLayout &layout) {
+void CoreChecks::SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state,
+                                    const VkImageLayout &layout) {
     assert(view_state);
 
-    IMAGE_STATE *image_state = GetImageState(device_data, view_state->create_info.image);
+    IMAGE_STATE *image_state = GetImageState(view_state->create_info.image);
     VkImageSubresourceRange sub_range = view_state->create_info.subresourceRange;
 
     // When changing the layout of a 3D image subresource via a 2D or 2D_ARRRAY image view, all depth slices of
@@ -314,27 +345,28 @@
     SetImageLayout(device_data, cb_node, image_state, sub_range, layout);
 }
 
-void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImageView imageView, const VkImageLayout &layout) {
-    auto view_state = GetImageViewState(device_data, imageView);
+void CoreChecks::SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImageView imageView,
+                                    const VkImageLayout &layout) {
+    auto view_state = GetImageViewState(imageView);
     SetImageViewLayout(device_data, cb_node, view_state, layout);
 }
 
-bool ValidateRenderPassLayoutAgainstFramebufferImageUsage(layer_data *device_data, RenderPassCreateVersion rp_version,
-                                                          VkImageLayout layout, VkImage image, VkImageView image_view,
-                                                          VkFramebuffer framebuffer, VkRenderPass renderpass,
-                                                          uint32_t attachment_index, const char *variable_name) {
+bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(layer_data *device_data, RenderPassCreateVersion rp_version,
+                                                                      VkImageLayout layout, VkImage image, VkImageView image_view,
+                                                                      VkFramebuffer framebuffer, VkRenderPass renderpass,
+                                                                      uint32_t attachment_index, const char *variable_name) {
     bool skip = false;
-    const auto report_data = core_validation::GetReportData(device_data);
-    auto image_state = GetImageState(device_data, image);
+    auto image_state = GetImageState(image);
     const char *vuid;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
 
     if (!image_state) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
                         "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
-                        "Render Pass begin with renderpass 0x%" PRIx64 " uses framebuffer 0x%" PRIx64 " where pAttachments[%" PRIu32
-                        "] = image view 0x%" PRIx64 ", which refers to an invalid image",
-                        HandleToUint64(renderpass), HandleToUint64(framebuffer), attachment_index, HandleToUint64(image_view));
+                        "Render Pass begin with renderpass %s uses framebuffer %s where pAttachments[%" PRIu32
+                        "] = image view %s, which refers to an invalid image",
+                        report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(framebuffer).c_str(),
+                        attachment_index, report_data->FormatHandle(image_view).c_str());
         return skip;
     }
 
@@ -345,11 +377,11 @@
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895";
         skip |=
             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
-                    "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                    " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
+                    "Layout/usage mismatch for attachment %u in render pass %s"
+                    " - the %s is %s but the image attached to framebuffer %s via image view %s"
                     " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT",
-                    attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                    HandleToUint64(renderpass), HandleToUint64(image_view));
+                    attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
+                    report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
     }
 
     if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
@@ -357,49 +389,49 @@
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897";
         skip |=
             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
-                    "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                    " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
+                    "Layout/usage mismatch for attachment %u in render pass %s"
+                    " - the %s is %s but the image attached to framebuffer %s via image view %s"
                     " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT",
-                    attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                    HandleToUint64(renderpass), HandleToUint64(image_view));
+                    attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
+                    report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
     }
 
     if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898";
         skip |=
             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
-                    "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                    " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
+                    "Layout/usage mismatch for attachment %u in render pass %s"
+                    " - the %s is %s but the image attached to framebuffer %s via image view %s"
                     " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT",
-                    attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                    HandleToUint64(renderpass), HandleToUint64(image_view));
+                    attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
+                    report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
     }
 
     if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899";
         skip |=
             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
-                    "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                    " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
+                    "Layout/usage mismatch for attachment %u in render pass %s"
+                    " - the %s is %s but the image attached to framebuffer %s via image view %s"
                     " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT",
-                    attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                    HandleToUint64(renderpass), HandleToUint64(image_view));
+                    attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
+                    report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
     }
 
-    if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) {
+    if (GetDeviceExtensions()->vk_khr_maintenance2) {
         if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
              layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
             vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758";
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                            HandleToUint64(image), vuid,
-                            "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                            " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
-                            " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
-                            attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                            HandleToUint64(renderpass), HandleToUint64(image_view));
+            skip |= log_msg(
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
+                "Layout/usage mismatch for attachment %u in render pass %s"
+                " - the %s is %s but the image attached to framebuffer %s via image view %s"
+                " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
+                attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
+                report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
         }
     } else {
         // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here.
@@ -408,25 +440,25 @@
             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(image), "VUID-vkCmdBeginRenderPass-initialLayout-00896",
-                            "Layout/usage mismatch for attachment %u in render pass 0x%" PRIx64
-                            " - the %s is %s but the image attached to framebuffer 0x%" PRIx64 " via image view 0x%" PRIx64
+                            "Layout/usage mismatch for attachment %u in render pass %s"
+                            " - the %s is %s but the image attached to framebuffer %s via image view %s"
                             " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
-                            attachment_index, HandleToUint64(framebuffer), variable_name, string_VkImageLayout(layout),
-                            HandleToUint64(renderpass), HandleToUint64(image_view));
+                            attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name,
+                            string_VkImageLayout(layout), report_data->FormatHandle(renderpass).c_str(),
+                            report_data->FormatHandle(image_view).c_str());
         }
     }
     return skip;
 }
 
-bool VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, RenderPassCreateVersion rp_version, GLOBAL_CB_NODE *pCB,
-                                           const VkRenderPassBeginInfo *pRenderPassBegin,
-                                           const FRAMEBUFFER_STATE *framebuffer_state) {
+bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, RenderPassCreateVersion rp_version,
+                                                       GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
+                                                       const FRAMEBUFFER_STATE *framebuffer_state) {
     bool skip = false;
-    auto const pRenderPassInfo = GetRenderPassState(device_data, pRenderPassBegin->renderPass)->createInfo.ptr();
+    auto const pRenderPassInfo = GetRenderPassState(pRenderPassBegin->renderPass)->createInfo.ptr();
     auto const &framebufferInfo = framebuffer_state->createInfo;
-    const auto report_data = core_validation::GetReportData(device_data);
 
-    auto render_pass = GetRenderPassState(device_data, pRenderPassBegin->renderPass)->renderPass;
+    auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass)->renderPass;
     auto framebuffer = framebuffer_state->framebuffer;
 
     if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
@@ -436,14 +468,15 @@
     }
     for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
         const VkImageView &image_view = framebufferInfo.pAttachments[i];
-        auto view_state = GetImageViewState(device_data, image_view);
+        auto view_state = GetImageViewState(image_view);
 
         if (!view_state) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
-                            "vkCmdBeginRenderPass() :framebuffer 0x%" PRIx64 " pAttachments[%" PRIu32 "] = 0x%" PRIx64
-                            " is not a valid VkImageView handle",
-                            HandleToUint64(framebuffer_state->framebuffer), i, HandleToUint64(image_view));
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
+                        HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
+                        "vkCmdBeginRenderPass(): framebuffer %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle",
+                        report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
+                        report_data->FormatHandle(image_view).c_str());
             continue;
         }
 
@@ -487,7 +520,7 @@
             auto &attachment_ref = subpass.pInputAttachments[k];
             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
-                auto view_state = GetImageViewState(device_data, image_view);
+                auto view_state = GetImageViewState(image_view);
 
                 if (view_state) {
                     auto image = view_state->create_info.image;
@@ -502,7 +535,7 @@
             auto &attachment_ref = subpass.pColorAttachments[k];
             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
-                auto view_state = GetImageViewState(device_data, image_view);
+                auto view_state = GetImageViewState(image_view);
 
                 if (view_state) {
                     auto image = view_state->create_info.image;
@@ -522,7 +555,7 @@
             auto &attachment_ref = *subpass.pDepthStencilAttachment;
             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
-                auto view_state = GetImageViewState(device_data, image_view);
+                auto view_state = GetImageViewState(image_view);
 
                 if (view_state) {
                     auto image = view_state->create_info.image;
@@ -536,18 +569,18 @@
     return skip;
 }
 
-void TransitionAttachmentRefLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
-                                   const safe_VkAttachmentReference2KHR &ref) {
+void CoreChecks::TransitionAttachmentRefLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
+                                               const safe_VkAttachmentReference2KHR &ref) {
     if (ref.attachment != VK_ATTACHMENT_UNUSED) {
-        auto image_view = GetAttachmentImageViewState(device_data, pFramebuffer, ref.attachment);
+        auto image_view = GetAttachmentImageViewState(pFramebuffer, ref.attachment);
         if (image_view) {
             SetImageViewLayout(device_data, pCB, image_view, ref.layout);
         }
     }
 }
 
-void TransitionSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, const RENDER_PASS_STATE *render_pass_state,
-                              const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
+void CoreChecks::TransitionSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, const RENDER_PASS_STATE *render_pass_state,
+                                          const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
     assert(render_pass_state);
 
     if (framebuffer_state) {
@@ -564,8 +597,9 @@
     }
 }
 
-bool ValidateImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE const *pCB, const VkImageMemoryBarrier *mem_barrier,
-                               uint32_t level, uint32_t layer, VkImageAspectFlags aspect) {
+bool CoreChecks::ValidateImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE const *pCB,
+                                           const VkImageMemoryBarrier *mem_barrier, uint32_t level, uint32_t layer,
+                                           VkImageAspectFlags aspect) {
     if (!(mem_barrier->subresourceRange.aspectMask & aspect)) {
         return false;
     }
@@ -578,13 +612,12 @@
     if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
         // TODO: Set memory invalid which is in mem_tracker currently
     } else if (node.layout != mem_barrier->oldLayout) {
-        skip = log_msg(core_validation::GetReportData(device_data), VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                       VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer),
-                       "VUID-VkImageMemoryBarrier-oldLayout-01197",
-                       "For image 0x%" PRIx64
-                       " you cannot transition the layout of aspect=%d level=%d layer=%d from %s when current layout is %s.",
-                       HandleToUint64(mem_barrier->image), aspect, level, layer, string_VkImageLayout(mem_barrier->oldLayout),
-                       string_VkImageLayout(node.layout));
+        skip = log_msg(
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            HandleToUint64(pCB->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
+            "For image %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when current layout is %s.",
+            report_data->FormatHandle(mem_barrier->image).c_str(), aspect, level, layer,
+            string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
     }
     return skip;
 }
@@ -592,12 +625,13 @@
 // Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
 // 1. Transition into initialLayout state
 // 2. Transition from initialLayout to layout used in subpass 0
-void TransitionBeginRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state, const RENDER_PASS_STATE *render_pass_state,
-                                      FRAMEBUFFER_STATE *framebuffer_state) {
+void CoreChecks::TransitionBeginRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
+                                                  const RENDER_PASS_STATE *render_pass_state,
+                                                  FRAMEBUFFER_STATE *framebuffer_state) {
     // First transition into initialLayout
     auto const rpci = render_pass_state->createInfo.ptr();
     for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
-        auto view_state = GetAttachmentImageViewState(device_data, framebuffer_state, i);
+        auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
         if (view_state) {
             SetImageViewLayout(device_data, cb_state, view_state, rpci->pAttachments[i].initialLayout);
         }
@@ -606,8 +640,9 @@
     TransitionSubpassLayouts(device_data, cb_state, render_pass_state, 0, framebuffer_state);
 }
 
-void TransitionImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier,
-                                 uint32_t level, uint32_t layer, VkImageAspectFlags aspect_mask, VkImageAspectFlags aspect) {
+void CoreChecks::TransitionImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier,
+                                             uint32_t level, uint32_t layer, VkImageAspectFlags aspect_mask,
+                                             VkImageAspectFlags aspect) {
     if (!(aspect_mask & aspect)) {
         return;
     }
@@ -643,12 +678,11 @@
 }
 
 // Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
-bool ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier, bool new_not_old,
-                                       VkImageUsageFlags usage_flags, const char *func_name) {
-    const auto report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier,
+                                                   bool new_not_old, VkImageUsageFlags usage_flags, const char *func_name) {
     bool skip = false;
     const VkImageLayout layout = (new_not_old) ? img_barrier->newLayout : img_barrier->oldLayout;
-    std::string msg_code = kVUIDUndefined;  // sentinel value meaning "no error"
+    const char *msg_code = kVUIDUndefined;  // sentinel value meaning "no error"
 
     switch (layout) {
         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
@@ -694,9 +728,9 @@
     if (msg_code != kVUIDUndefined) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                         HandleToUint64(img_barrier->image), msg_code,
-                        "%s: Image barrier 0x%p %sLayout=%s is not compatible with image 0x%" PRIx64 " usage flags 0x%" PRIx32 ".",
-                        func_name, static_cast<const void *>(img_barrier), ((new_not_old) ? "new" : "old"),
-                        string_VkImageLayout(layout), HandleToUint64(img_barrier->image), usage_flags);
+                        "%s: Image barrier 0x%p %sLayout=%s is not compatible with image %s usage flags 0x%" PRIx32 ".", func_name,
+                        static_cast<const void *>(img_barrier), ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout),
+                        report_data->FormatHandle(img_barrier->image).c_str(), usage_flags);
     }
     return skip;
 }
@@ -712,8 +746,8 @@
 using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>;
 
 // Verify image barriers are compatible with the images they reference.
-bool ValidateBarriersToImages(layer_data *device_data, GLOBAL_CB_NODE const *cb_state, uint32_t imageMemoryBarrierCount,
-                              const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) {
+bool CoreChecks::ValidateBarriersToImages(layer_data *device_data, GLOBAL_CB_NODE const *cb_state, uint32_t imageMemoryBarrierCount,
+                                          const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) {
     bool skip = false;
 
     // Scoreboard for duplicate layout transition barriers within the list
@@ -739,15 +773,14 @@
                         (img_barrier->oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) {
                         const VkImageSubresourceRange &range = img_barrier->subresourceRange;
                         skip = log_msg(
-                            core_validation::GetReportData(device_data), VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_state->commandBuffer),
-                            "VUID-VkImageMemoryBarrier-oldLayout-01197",
-                            "%s: pImageMemoryBarrier[%u] conflicts with earlier entry pImageMemoryBarrier[%u]. Image 0x%" PRIx64
+                            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
+                            "%s: pImageMemoryBarrier[%u] conflicts with earlier entry pImageMemoryBarrier[%u]. Image %s"
                             " subresourceRange: aspectMask=%u baseMipLevel=%u levelCount=%u, baseArrayLayer=%u, layerCount=%u; "
                             "conflicting barrier transitions image layout from %s when earlier barrier transitioned to layout %s.",
-                            func_name, i, entry.index, HandleToUint64(img_barrier->image), range.aspectMask, range.baseMipLevel,
-                            range.levelCount, range.baseArrayLayer, range.layerCount, string_VkImageLayout(img_barrier->oldLayout),
-                            string_VkImageLayout(entry.barrier->newLayout));
+                            func_name, i, entry.index, report_data->FormatHandle(img_barrier->image).c_str(), range.aspectMask,
+                            range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount,
+                            string_VkImageLayout(img_barrier->oldLayout), string_VkImageLayout(entry.barrier->newLayout));
                     }
                     entry = new_entry;
                 } else {
@@ -758,7 +791,7 @@
             }
         }
 
-        auto image_state = GetImageState(device_data, img_barrier->image);
+        auto image_state = GetImageState(img_barrier->image);
         if (image_state) {
             VkImageUsageFlags usage_flags = image_state->createInfo.usage;
             skip |= ValidateBarrierLayoutToImageUsage(device_data, img_barrier, false, usage_flags, func_name);
@@ -768,29 +801,28 @@
             if (image_state->layout_locked) {
                 // TODO: Add unique id for error when available
                 skip |= log_msg(
-                    core_validation::GetReportData(device_data), VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(img_barrier->image), 0,
-                    "Attempting to transition shared presentable image 0x%" PRIx64
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                    HandleToUint64(img_barrier->image), 0,
+                    "Attempting to transition shared presentable image %s"
                     " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.",
-                    HandleToUint64(img_barrier->image), string_VkImageLayout(img_barrier->oldLayout),
+                    report_data->FormatHandle(img_barrier->image).c_str(), string_VkImageLayout(img_barrier->oldLayout),
                     string_VkImageLayout(img_barrier->newLayout));
             }
         }
 
-        VkImageCreateInfo *image_create_info = &(GetImageState(device_data, img_barrier->image)->createInfo);
+        VkImageCreateInfo *image_create_info = &(GetImageState(img_barrier->image)->createInfo);
         // For a Depth/Stencil image both aspects MUST be set
         if (FormatIsDepthAndStencil(image_create_info->format)) {
             auto const aspect_mask = img_barrier->subresourceRange.aspectMask;
             auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
             if ((aspect_mask & ds_mask) != (ds_mask)) {
-                skip |=
-                    log_msg(core_validation::GetReportData(device_data), VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(img_barrier->image),
-                            "VUID-VkImageMemoryBarrier-image-01207",
-                            "%s: Image barrier 0x%p references image 0x%" PRIx64
-                            " of format %s that must have the depth and stencil aspects set, but its aspectMask is 0x%" PRIx32 ".",
-                            func_name, static_cast<const void *>(img_barrier), HandleToUint64(img_barrier->image),
-                            string_VkFormat(image_create_info->format), aspect_mask);
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                                HandleToUint64(img_barrier->image), "VUID-VkImageMemoryBarrier-image-01207",
+                                "%s: Image barrier 0x%p references image %s of format %s that must have the depth and stencil "
+                                "aspects set, but its aspectMask is 0x%" PRIx32 ".",
+                                func_name, static_cast<const void *>(img_barrier),
+                                report_data->FormatHandle(img_barrier->image).c_str(), string_VkFormat(image_create_info->format),
+                                aspect_mask);
             }
         }
         uint32_t level_count = ResolveRemainingLevels(&img_barrier->subresourceRange, image_create_info->mipLevels);
@@ -804,7 +836,7 @@
                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
-                if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+                if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
                     skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer,
                                                       VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
                     skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer,
@@ -818,20 +850,19 @@
     return skip;
 }
 
-static bool IsReleaseOp(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkImageMemoryBarrier const *barrier) {
+bool CoreChecks::IsReleaseOp(GLOBAL_CB_NODE *cb_state, VkImageMemoryBarrier const *barrier) {
     if (!IsTransferOp(barrier)) return false;
 
-    auto pool = GetCommandPoolNode(device_data, cb_state->createInfo.commandPool);
-    return pool && IsReleaseOp<VkImageMemoryBarrier, true>(pool, barrier);
+    auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
+    return pool && TempIsReleaseOp<VkImageMemoryBarrier, true>(pool, barrier);
 }
 
 template <typename Barrier>
-bool ValidateQFOTransferBarrierUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
-                                          uint32_t barrier_count, const Barrier *barriers) {
+bool CoreChecks::ValidateQFOTransferBarrierUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
+                                                      uint32_t barrier_count, const Barrier *barriers) {
     using BarrierRecord = QFOTransferBarrier<Barrier>;
     bool skip = false;
-    const auto report_data = core_validation::GetReportData(device_data);
-    auto pool = GetCommandPoolNode(device_data, cb_state->createInfo.commandPool);
+    auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
     auto &barrier_sets = GetQFOBarrierSets(cb_state, typename BarrierRecord::Tag());
     const char *barrier_name = BarrierRecord::BarrierName();
     const char *handle_name = BarrierRecord::HandleName();
@@ -839,7 +870,8 @@
     for (uint32_t b = 0; b < barrier_count; b++) {
         if (!IsTransferOp(&barriers[b])) continue;
         const BarrierRecord *barrier_record = nullptr;
-        if (IsReleaseOp<Barrier, true /* Assume IsTransfer */>(pool, &barriers[b]) && !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
+        if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer */>(pool, &barriers[b]) &&
+            !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
             const auto found = barrier_sets.release.find(barriers[b]);
             if (found != barrier_sets.release.cend()) {
                 barrier_record = &(*found);
@@ -854,25 +886,27 @@
             }
         }
         if (barrier_record != nullptr) {
-            skip |=
-                log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                        HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInCB(),
-                        "%s: %s at index %" PRIu32 " %s queue ownership of %s (0x%" PRIx64 "), from srcQueueFamilyIndex %" PRIu32
-                        " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier recorded in this command buffer.",
-                        func_name, barrier_name, b, transfer_type, handle_name, HandleToUint64(barrier_record->handle),
-                        barrier_record->srcQueueFamilyIndex, barrier_record->dstQueueFamilyIndex);
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInCB(),
+                            "%s: %s at index %" PRIu32 " %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
+                            " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier recorded in this command buffer.",
+                            func_name, barrier_name, b, transfer_type, handle_name,
+                            report_data->FormatHandle(barrier_record->handle).c_str(), barrier_record->srcQueueFamilyIndex,
+                            barrier_record->dstQueueFamilyIndex);
         }
     }
     return skip;
 }
 
 template <typename Barrier>
-void RecordQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t barrier_count, const Barrier *barriers) {
-    auto pool = GetCommandPoolNode(device_data, cb_state->createInfo.commandPool);
+void CoreChecks::RecordQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t barrier_count,
+                                           const Barrier *barriers) {
+    auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
     auto &barrier_sets = GetQFOBarrierSets(cb_state, typename QFOTransferBarrier<Barrier>::Tag());
     for (uint32_t b = 0; b < barrier_count; b++) {
         if (!IsTransferOp(&barriers[b])) continue;
-        if (IsReleaseOp<Barrier, true /* Assume IsTransfer*/>(pool, &barriers[b]) && !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
+        if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer*/>(pool, &barriers[b]) &&
+            !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
             barrier_sets.release.emplace(barriers[b]);
         } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
                    !IsSpecial(barriers[b].srcQueueFamilyIndex)) {
@@ -881,51 +915,50 @@
     }
 }
 
-bool ValidateBarriersQFOTransferUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
-                                           uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
-                                           uint32_t imageMemBarrierCount, const VkImageMemoryBarrier *pImageMemBarriers) {
+bool CoreChecks::ValidateBarriersQFOTransferUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
+                                                       uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
+                                                       uint32_t imageMemBarrierCount,
+                                                       const VkImageMemoryBarrier *pImageMemBarriers) {
     bool skip = false;
     skip |= ValidateQFOTransferBarrierUniqueness(device_data, func_name, cb_state, bufferBarrierCount, pBufferMemBarriers);
     skip |= ValidateQFOTransferBarrierUniqueness(device_data, func_name, cb_state, imageMemBarrierCount, pImageMemBarriers);
     return skip;
 }
 
-void RecordBarriersQFOTransfers(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
-                                uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
-                                uint32_t imageMemBarrierCount, const VkImageMemoryBarrier *pImageMemBarriers) {
+void CoreChecks::RecordBarriersQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t bufferBarrierCount,
+                                            const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
+                                            const VkImageMemoryBarrier *pImageMemBarriers) {
     RecordQFOTransferBarriers(device_data, cb_state, bufferBarrierCount, pBufferMemBarriers);
     RecordQFOTransferBarriers(device_data, cb_state, imageMemBarrierCount, pImageMemBarriers);
 }
 
 template <typename BarrierRecord, typename Scoreboard>
-static bool ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const GLOBAL_CB_NODE *cb_state,
-                                           const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) {
+bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const GLOBAL_CB_NODE *cb_state,
+                                                const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) {
     // Record to the scoreboard or report that we have a duplication
     bool skip = false;
     auto inserted = scoreboard->insert(std::make_pair(barrier, cb_state));
     if (!inserted.second && inserted.first->second != cb_state) {
         // This is a duplication (but don't report duplicates from the same CB, as we do that at record time
-        skip = log_msg(
-            report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-            HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInSubmit(),
-            "%s: %s %s queue ownership of %s (0x%" PRIx64 "), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
-            " duplicates existing barrier submitted in this batch from command buffer 0x%" PRIx64 ".",
-            "vkQueueSubmit()", BarrierRecord::BarrierName(), operation, BarrierRecord::HandleName(), HandleToUint64(barrier.handle),
-            barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex, HandleToUint64(inserted.first->second));
+        skip = log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                       HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInSubmit(),
+                       "%s: %s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
+                       " duplicates existing barrier submitted in this batch from command buffer %s.",
+                       "vkQueueSubmit()", BarrierRecord::BarrierName(), operation, BarrierRecord::HandleName(),
+                       report_data->FormatHandle(barrier.handle).c_str(), barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex,
+                       report_data->FormatHandle(inserted.first->second).c_str());
     }
     return skip;
 }
 
 template <typename Barrier>
-static bool ValidateQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
-                                              QFOTransferCBScoreboards<Barrier> *scoreboards) {
+bool CoreChecks::ValidateQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
+                                                   QFOTransferCBScoreboards<Barrier> *scoreboards) {
     using BarrierRecord = QFOTransferBarrier<Barrier>;
     using TypeTag = typename BarrierRecord::Tag;
     bool skip = false;
-    const auto report_data = core_validation::GetReportData(device_data);
     const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
-    const GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers =
-        core_validation::GetGlobalQFOReleaseBarrierMap(device_data, TypeTag());
+    const GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
     const char *barrier_name = BarrierRecord::BarrierName();
     const char *handle_name = BarrierRecord::HandleName();
     // No release should have an extant duplicate (WARNING)
@@ -938,10 +971,10 @@
             if (found != set_for_handle.cend()) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOSubmitted(),
-                                "%s: %s releasing queue ownership of %s (0x%" PRIx64 "), from srcQueueFamilyIndex %" PRIu32
+                                "%s: %s releasing queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
                                 " to dstQueueFamilyIndex %" PRIu32
                                 " duplicates existing barrier queued for execution, without intervening acquire operation.",
-                                "vkQueueSubmit()", barrier_name, handle_name, HandleToUint64(found->handle),
+                                "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(found->handle).c_str(),
                                 found->srcQueueFamilyIndex, found->dstQueueFamilyIndex);
             }
         }
@@ -958,10 +991,9 @@
         if (!matching_release_found) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgMissingQFOReleaseInSubmit(),
-                            "%s: in submitted command buffer %s aquiring ownership of %s (0x%" PRIx64
-                            "), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
-                            " has no matching release barrier queued for execution.",
-                            "vkQueueSubmit()", barrier_name, handle_name, HandleToUint64(acquire.handle),
+                            "%s: in submitted command buffer %s acquiring ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
+                            " to dstQueueFamilyIndex %" PRIu32 " has no matching release barrier queued for execution.",
+                            "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(acquire.handle).c_str(),
                             acquire.srcQueueFamilyIndex, acquire.dstQueueFamilyIndex);
         }
         skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "acquiring", acquire, &scoreboards->acquire);
@@ -969,9 +1001,9 @@
     return skip;
 }
 
-bool ValidateQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
-                                QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
-                                QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) {
+bool CoreChecks::ValidateQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
+                                            QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
+                                            QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) {
     bool skip = false;
     skip |= ValidateQueuedQFOTransferBarriers<VkImageMemoryBarrier>(device_data, cb_state, qfo_image_scoreboards);
     skip |= ValidateQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(device_data, cb_state, qfo_buffer_scoreboards);
@@ -979,12 +1011,11 @@
 }
 
 template <typename Barrier>
-static void RecordQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
+void CoreChecks::RecordQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
     using BarrierRecord = QFOTransferBarrier<Barrier>;
     using TypeTag = typename BarrierRecord::Tag;
     const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
-    GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers =
-        core_validation::GetGlobalQFOReleaseBarrierMap(device_data, TypeTag());
+    GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
 
     // Add release barriers from this submit to the global map
     for (const auto &release : cb_barriers.release) {
@@ -1007,28 +1038,18 @@
     }
 }
 
-void RecordQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
+void CoreChecks::RecordQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
     RecordQueuedQFOTransferBarriers<VkImageMemoryBarrier>(device_data, cb_state);
     RecordQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(device_data, cb_state);
 }
 
-// Remove the pending QFO release records from the global set
-// Note that the type of the handle argument constrained to match Barrier type
-// The defaulted BarrierRecord argument allows use to declare the type once, but is not intended to be specified by the caller
-template <typename Barrier, typename BarrierRecord = QFOTransferBarrier<Barrier>>
-static void EraseQFOReleaseBarriers(layer_data *device_data, const typename BarrierRecord::HandleType &handle) {
-    GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers =
-        core_validation::GetGlobalQFOReleaseBarrierMap(device_data, typename BarrierRecord::Tag());
-    global_release_barriers.erase(handle);
-}
-
 // Avoid making the template globally visible by exporting the one instance of it we need.
-void EraseQFOImageRelaseBarriers(layer_data *device_data, const VkImage &image) {
+void CoreChecks::EraseQFOImageRelaseBarriers(layer_data *device_data, const VkImage &image) {
     EraseQFOReleaseBarriers<VkImageMemoryBarrier>(device_data, image);
 }
 
-void TransitionImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t memBarrierCount,
-                            const VkImageMemoryBarrier *pImgMemBarriers) {
+void CoreChecks::TransitionImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t memBarrierCount,
+                                        const VkImageMemoryBarrier *pImgMemBarriers) {
     for (uint32_t i = 0; i < memBarrierCount; ++i) {
         auto mem_barrier = &pImgMemBarriers[i];
         if (!mem_barrier) continue;
@@ -1040,11 +1061,11 @@
         // purposes it doesn't seem important which side performs the layout
         // transition, but it must not be performed twice. We'll arbitrarily
         // choose to perform it as part of the acquire operation.
-        if (IsReleaseOp(device_data, cb_state, mem_barrier)) {
+        if (IsReleaseOp(cb_state, mem_barrier)) {
             continue;
         }
 
-        VkImageCreateInfo *image_create_info = &(GetImageState(device_data, mem_barrier->image)->createInfo);
+        VkImageCreateInfo *image_create_info = &(GetImageState(mem_barrier->image)->createInfo);
         uint32_t level_count = ResolveRemainingLevels(&mem_barrier->subresourceRange, image_create_info->mipLevels);
         uint32_t layer_count = ResolveRemainingLayers(&mem_barrier->subresourceRange, image_create_info->arrayLayers);
 
@@ -1058,7 +1079,7 @@
 
         // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes
         VkImageAspectFlags aspect_mask = mem_barrier->subresourceRange.aspectMask;
-        if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+        if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
             if (FormatIsMultiplane(image_create_info->format)) {
                 if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
                     aspect_mask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
@@ -1082,7 +1103,7 @@
                                             VK_IMAGE_ASPECT_STENCIL_BIT);
                 TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
                                             VK_IMAGE_ASPECT_METADATA_BIT);
-                if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+                if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
                     TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
                                                 VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
                     TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
@@ -1095,11 +1116,10 @@
     }
 }
 
-bool VerifyImageLayout(layer_data const *device_data, GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state,
-                       VkImageSubresourceLayers subLayers, VkImageLayout explicit_layout, VkImageLayout optimal_layout,
-                       const char *caller, const std::string &layout_invalid_msg_code, const std::string &layout_mismatch_msg_code,
-                       bool *error) {
-    const auto report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::VerifyImageLayout(layer_data const *device_data, GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state,
+                                   VkImageSubresourceLayers subLayers, VkImageLayout explicit_layout, VkImageLayout optimal_layout,
+                                   const char *caller, const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code,
+                                   bool *error) {
     const auto image = image_state->image;
     bool skip = false;
 
@@ -1112,10 +1132,10 @@
                 *error = true;
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), layout_mismatch_msg_code,
-                                "%s: Cannot use image 0x%" PRIx64
-                                " (layer=%u mip=%u) with specific layout %s that doesn't match the actual current layout %s.",
-                                caller, HandleToUint64(image), layer, subLayers.mipLevel, string_VkImageLayout(explicit_layout),
-                                string_VkImageLayout(node.layout));
+                                "%s: Cannot use image %s (layer=%u mip=%u) with specific layout %s that doesn't match the actual "
+                                "current layout %s.",
+                                caller, report_data->FormatHandle(image).c_str(), layer, subLayers.mipLevel,
+                                string_VkImageLayout(explicit_layout), string_VkImageLayout(node.layout));
             }
         }
     }
@@ -1127,10 +1147,10 @@
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_node->commandBuffer),
                                 kVUID_Core_DrawState_InvalidImageLayout,
-                                "%s: For optimal performance image 0x%" PRIx64 " layout should be %s instead of GENERAL.", caller,
-                                HandleToUint64(image), string_VkImageLayout(optimal_layout));
+                                "%s: For optimal performance image %s layout should be %s instead of GENERAL.", caller,
+                                report_data->FormatHandle(image).c_str(), string_VkImageLayout(optimal_layout));
             }
-        } else if (GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image) {
+        } else if (GetDeviceExtensions()->vk_khr_shared_presentable_image) {
             if (image_state->shared_presentable) {
                 if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != explicit_layout) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -1143,22 +1163,24 @@
             *error = true;
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), layout_invalid_msg_code,
-                            "%s: Layout for image 0x%" PRIx64 " is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
-                            HandleToUint64(image), string_VkImageLayout(explicit_layout), string_VkImageLayout(optimal_layout));
+                            "%s: Layout for image %s is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
+                            report_data->FormatHandle(image).c_str(), string_VkImageLayout(explicit_layout),
+                            string_VkImageLayout(optimal_layout));
         }
     }
     return skip;
 }
 
-void TransitionFinalSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
-                                   FRAMEBUFFER_STATE *framebuffer_state) {
-    auto renderPass = GetRenderPassState(device_data, pRenderPassBegin->renderPass);
+void CoreChecks::TransitionFinalSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
+                                               const VkRenderPassBeginInfo *pRenderPassBegin,
+                                               FRAMEBUFFER_STATE *framebuffer_state) {
+    auto renderPass = GetRenderPassState(pRenderPassBegin->renderPass);
     if (!renderPass) return;
 
     const VkRenderPassCreateInfo2KHR *pRenderPassInfo = renderPass->createInfo.ptr();
     if (framebuffer_state) {
         for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
-            auto view_state = GetAttachmentImageViewState(device_data, framebuffer_state, i);
+            auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
             if (view_state) {
                 SetImageViewLayout(device_data, pCB, view_state, pRenderPassInfo->pAttachments[i].finalLayout);
             }
@@ -1166,96 +1188,275 @@
     }
 }
 
-bool PreCallValidateCreateImage(layer_data *device_data, const VkImageCreateInfo *pCreateInfo,
-                                const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+// Android-specific validation that uses types defined only with VK_USE_PLATFORM_ANDROID_KHR
+// This could also move into a seperate core_validation_android.cpp file... ?
+
+//
+// AHB-specific validation within non-AHB APIs
+//
+bool CoreChecks::ValidateCreateImageANDROID(layer_data *device_data, const debug_report_data *report_data,
+                                            const VkImageCreateInfo *create_info) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
-    if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
-        skip |=
-            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    "VUID-VkImageCreateInfo-format-00943", "vkCreateImage: VkFormat for image must not be VK_FORMAT_UNDEFINED.");
+    const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
+    if (ext_fmt_android) {
+        if (0 != ext_fmt_android->externalFormat) {
+            if (VK_FORMAT_UNDEFINED != create_info->format) {
+                skip |=
+                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkImageCreateInfo-pNext-01974",
+                            "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with non-zero "
+                            "externalFormat, but the VkImageCreateInfo's format is not VK_FORMAT_UNDEFINED.");
+            }
 
-        return skip;
+            if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info->flags)) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkImageCreateInfo-pNext-02396",
+                                "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
+                                "non-zero externalFormat, but flags include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
+            }
+
+            if (0 != (~VK_IMAGE_USAGE_SAMPLED_BIT & create_info->usage)) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkImageCreateInfo-pNext-02397",
+                                "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
+                                "non-zero externalFormat, but usage includes bits other than VK_IMAGE_USAGE_SAMPLED_BIT.");
+            }
+
+            if (VK_IMAGE_TILING_OPTIMAL != create_info->tiling) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkImageCreateInfo-pNext-02398",
+                                "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
+                                "non-zero externalFormat, but layout is not VK_IMAGE_TILING_OPTIMAL.");
+            }
+        }
+
+        auto ahb_formats = GetAHBExternalFormatsSet();
+        if ((0 != ext_fmt_android->externalFormat) && (0 == ahb_formats->count(ext_fmt_android->externalFormat))) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkExternalFormatANDROID-externalFormat-01894",
+                            "vkCreateImage(): Chained VkExternalFormatANDROID struct contains a non-zero externalFormat which has "
+                            "not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().");
+        }
     }
 
-    const char *format_string = string_VkFormat(pCreateInfo->format);
+    if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
+        if (VK_FORMAT_UNDEFINED == create_info->format) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkImageCreateInfo-pNext-01975",
+                            "vkCreateImage(): VkImageCreateInfo struct's format is VK_FORMAT_UNDEFINED, but either does not have a "
+                            "chained VkExternalFormatANDROID struct or the struct exists but has an externalFormat of 0.");
+        }
+    }
+
+    const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
+    if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
+        if (create_info->imageType != VK_IMAGE_TYPE_2D) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkImageCreateInfo-pNext-02393",
+                        "vkCreateImage(): VkImageCreateInfo struct with imageType %s has chained VkExternalMemoryImageCreateInfo "
+                        "struct with handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
+                        string_VkImageType(create_info->imageType));
+        }
+
+        if ((create_info->mipLevels != 1) && (create_info->mipLevels != FullMipChainLevels(create_info->extent))) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkImageCreateInfo-pNext-02394",
+                            "vkCreateImage(): VkImageCreateInfo struct with chained VkExternalMemoryImageCreateInfo struct of "
+                            "handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID "
+                            "specifies mipLevels = %" PRId32 " (full chain mipLevels are %" PRId32 ").",
+                            create_info->mipLevels, FullMipChainLevels(create_info->extent));
+        }
+    }
+
+    return skip;
+}
+
+void CoreChecks::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {
+    const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
+    if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
+        is_node->imported_ahb = true;
+    }
+    const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
+    if (ext_fmt_android && (0 != ext_fmt_android->externalFormat)) {
+        is_node->has_ahb_format = true;
+        is_node->ahb_format = ext_fmt_android->externalFormat;
+    }
+}
+
+bool CoreChecks::ValidateCreateImageViewANDROID(layer_data *device_data, const VkImageViewCreateInfo *create_info) {
+    bool skip = false;
+    IMAGE_STATE *image_state = GetImageState(create_info->image);
+
+    if (image_state->has_ahb_format) {
+        if (VK_FORMAT_UNDEFINED != create_info->format) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02399",
+                            "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
+                            "format member is %s.",
+                            string_VkFormat(create_info->format));
+        }
+
+        // Chain must include a compatible ycbcr conversion
+        bool conv_found = false;
+        uint64_t external_format = 0;
+        const VkSamplerYcbcrConversionInfo *ycbcr_conv_info = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info->pNext);
+        if (ycbcr_conv_info != nullptr) {
+            VkSamplerYcbcrConversion conv_handle = ycbcr_conv_info->conversion;
+            auto fmap = GetYcbcrConversionFormatMap();
+            if (fmap->find(conv_handle) != fmap->end()) {
+                conv_found = true;
+                external_format = fmap->at(conv_handle);
+            }
+        }
+        if ((!conv_found) || (external_format != image_state->ahb_format)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02400",
+                            "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
+                            "without a chained VkSamplerYcbcrConversionInfo struct with the same external format.");
+        }
+
+        // Errors in create_info swizzles
+        if ((create_info->components.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
+            (create_info->components.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
+            (create_info->components.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
+            (create_info->components.a != VK_COMPONENT_SWIZZLE_IDENTITY)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02401",
+                            "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
+                            "includes one or more non-identity component swizzles.");
+        }
+    }
+
+    return skip;
+}
+
+bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(layer_data *device_data, const VkImage image) {
+    bool skip = false;
+
+    IMAGE_STATE *image_state = GetImageState(image);
+    if (image_state->imported_ahb && (0 == image_state->GetBoundMemory().size())) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
+                        "VUID-vkGetImageSubresourceLayout-image-01895",
+                        "vkGetImageSubresourceLayout(): Attempt to query layout from an image created with "
+                        "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType which has not yet been "
+                        "bound to memory.");
+    }
+    return skip;
+}
+
+#else
+
+bool CoreChecks::ValidateCreateImageANDROID(layer_data *device_data, const debug_report_data *report_data,
+                                            const VkImageCreateInfo *create_info) {
+    return false;
+}
+
+void CoreChecks::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {}
+
+bool CoreChecks::ValidateCreateImageViewANDROID(layer_data *device_data, const VkImageViewCreateInfo *create_info) { return false; }
+
+bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(layer_data *device_data, const VkImage image) { return false; }
+
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        skip |= ValidateCreateImageANDROID(device_data, report_data, pCreateInfo);
+    } else {  // These checks are omitted or replaced when Android HW Buffer extension is active
+        if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
+            return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                           "VUID-VkImageCreateInfo-format-00943",
+                           "vkCreateImage(): VkFormat for image must not be VK_FORMAT_UNDEFINED.");
+        }
+    }
 
     if ((pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && (VK_IMAGE_TYPE_2D != pCreateInfo->imageType)) {
-        std::stringstream ss;
-        ss << "vkCreateImage: Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT flag bit is set";
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkImageCreateInfo-flags-00949", "%s.", ss.str().c_str());
+        skip |= log_msg(
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            "VUID-VkImageCreateInfo-flags-00949",
+            "vkCreateImage(): Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT flag bit is set");
     }
 
-    const VkPhysicalDeviceLimits *device_limits = &(GetPhysicalDeviceProperties(device_data)->limits);
-    VkImageFormatProperties format_limits;  // Format limits may exceed general device limits
-    GetImageFormatProperties(device_data, pCreateInfo, &format_limits);
-
-    if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
-        std::stringstream ss;
-        ss << "vkCreateImage: Image mip levels exceed image format maxMipLevels for format " << format_string;
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkImageCreateInfo-mipLevels-02255", "%s.", ss.str().c_str());
-    }
-
+    const VkPhysicalDeviceLimits *device_limits = &(GetPDProperties()->limits);
     VkImageUsageFlags attach_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
                                      VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.width > device_limits->maxFramebufferWidth)) {
-        std::stringstream ss;
-        ss << "vkCreateImage: Image usage flags include a frame buffer attachment bit and image width exceeds device "
-              "maxFramebufferWidth";
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkImageCreateInfo-usage-00964", "%s.", ss.str().c_str());
+                        "VUID-VkImageCreateInfo-usage-00964",
+                        "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image width exceeds device "
+                        "maxFramebufferWidth.");
     }
 
     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.height > device_limits->maxFramebufferHeight)) {
-        std::stringstream ss;
-        ss << "vkCreateImage: Image usage flags include a frame buffer attachment bit and image height exceeds device "
-              "maxFramebufferHeight";
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkImageCreateInfo-usage-00965", "%s.", ss.str().c_str());
+                        "VUID-VkImageCreateInfo-usage-00965",
+                        "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image height exceeds device "
+                        "maxFramebufferHeight");
     }
 
-    uint64_t total_size = (uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height *
-                          (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers *
-                          (uint64_t)pCreateInfo->samples * (uint64_t)FormatSize(pCreateInfo->format);
+    VkImageFormatProperties format_limits = {};
+    VkResult res = GetPDImageFormatProperties(pCreateInfo, &format_limits);
+    if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
+                        "vkCreateImage(): Format %s is not supported for this combination of parameters.",
+                        string_VkFormat(pCreateInfo->format));
+    } else {
+        if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
+            const char *format_string = string_VkFormat(pCreateInfo->format);
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkImageCreateInfo-mipLevels-02255",
+                            "vkCreateImage(): Image mip levels=%d exceed image format maxMipLevels=%d for format %s.",
+                            pCreateInfo->mipLevels, format_limits.maxMipLevels, format_string);
+        }
 
-    // Round up to imageGranularity boundary
-    VkDeviceSize imageGranularity = GetPhysicalDeviceProperties(device_data)->limits.bufferImageGranularity;
-    uint64_t ig_mask = imageGranularity - 1;
-    total_size = (total_size + ig_mask) & ~ig_mask;
+        uint64_t texel_count = (uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height *
+                               (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers *
+                               (uint64_t)pCreateInfo->samples;
+        uint64_t total_size = (uint64_t)std::ceil(FormatTexelSize(pCreateInfo->format) * texel_count);
 
-    if (total_size > format_limits.maxResourceSize) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
-                        kVUID_Core_Image_InvalidFormatLimitsViolation,
-                        "CreateImage resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
-                        ", maximum resource size = 0x%" PRIxLEAST64 " ",
-                        total_size, format_limits.maxResourceSize);
-    }
+        // Round up to imageGranularity boundary
+        VkDeviceSize imageGranularity = GetPDProperties()->limits.bufferImageGranularity;
+        uint64_t ig_mask = imageGranularity - 1;
+        total_size = (total_size + ig_mask) & ~ig_mask;
 
-    if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
-                        "VUID-VkImageCreateInfo-arrayLayers-02256",
-                        "CreateImage arrayLayers=%d exceeds allowable maximum supported by format of %d.", pCreateInfo->arrayLayers,
-                        format_limits.maxArrayLayers);
-    }
+        if (total_size > format_limits.maxResourceSize) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
+                            kVUID_Core_Image_InvalidFormatLimitsViolation,
+                            "vkCreateImage(): resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
+                            ", maximum resource size = 0x%" PRIxLEAST64 " ",
+                            total_size, format_limits.maxResourceSize);
+        }
 
-    if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
-                        "VUID-VkImageCreateInfo-samples-02258", "CreateImage samples %s is not supported by format 0x%.8X.",
+        if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
+                            "VUID-VkImageCreateInfo-arrayLayers-02256",
+                            "vkCreateImage(): arrayLayers=%d exceeds allowable maximum supported by format of %d.",
+                            pCreateInfo->arrayLayers, format_limits.maxArrayLayers);
+        }
+
+        if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
+                        "VUID-VkImageCreateInfo-samples-02258", "vkCreateImage(): samples %s is not supported by format 0x%.8X.",
                         string_VkSampleCountFlagBits(pCreateInfo->samples), format_limits.sampleCounts);
+        }
     }
 
-    if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) &&
-        (!GetEnabledFeatures(device_data)->core.sparseResidencyAliased)) {
+    if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && (!GetEnabledFeatures()->core.sparseResidencyAliased)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkImageCreateInfo-flags-01924",
                         "vkCreateImage(): the sparseResidencyAliased device feature is disabled: Images cannot be created with the "
                         "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT set.");
     }
 
-    if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) {
+    if (GetDeviceExtensions()->vk_khr_maintenance2) {
         if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR) {
             if (!(FormatIsCompressed_BC(pCreateInfo->format) || FormatIsCompressed_ASTC_LDR(pCreateInfo->format) ||
                   FormatIsCompressed_ETC2_EAC(pCreateInfo->format))) {
@@ -1276,60 +1477,73 @@
         }
     }
 
+    if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
+        skip |=
+            ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
+                                  "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", "VUID-VkImageCreateInfo-sharingMode-01420",
+                                  "VUID-VkImageCreateInfo-sharingMode-01420", false);
+    }
+
     return skip;
 }
 
-void PostCallRecordCreateImage(layer_data *device_data, const VkImageCreateInfo *pCreateInfo, VkImage *pImage) {
+void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
+    if (VK_SUCCESS != result) return;
     IMAGE_LAYOUT_NODE image_state;
     image_state.layout = pCreateInfo->initialLayout;
     image_state.format = pCreateInfo->format;
-    GetImageMap(device_data)->insert(std::make_pair(*pImage, std::unique_ptr<IMAGE_STATE>(new IMAGE_STATE(*pImage, pCreateInfo))));
+    IMAGE_STATE *is_node = new IMAGE_STATE(*pImage, pCreateInfo);
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        RecordCreateImageANDROID(pCreateInfo, is_node);
+    }
+    GetImageMap()->insert(std::make_pair(*pImage, std::unique_ptr<IMAGE_STATE>(is_node)));
     ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()};
-    (*core_validation::GetImageSubresourceMap(device_data))[*pImage].push_back(subpair);
-    (*core_validation::GetImageLayoutMap(device_data))[subpair] = image_state;
+    (*GetImageSubresourceMap())[*pImage].push_back(subpair);
+    (*GetImageLayoutMap())[subpair] = image_state;
 }
 
-bool PreCallValidateDestroyImage(layer_data *device_data, VkImage image, IMAGE_STATE **image_state, VK_OBJECT *obj_struct) {
-    const CHECK_DISABLED *disabled = core_validation::GetDisables(device_data);
-    *image_state = core_validation::GetImageState(device_data, image);
-    *obj_struct = {HandleToUint64(image), kVulkanObjectTypeImage};
-    if (disabled->destroy_image) return false;
+bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    IMAGE_STATE *image_state = GetImageState(image);
+    const VK_OBJECT obj_struct = {HandleToUint64(image), kVulkanObjectTypeImage};
     bool skip = false;
-    if (*image_state) {
-        skip |= core_validation::ValidateObjectNotInUse(device_data, *image_state, *obj_struct, "vkDestroyImage",
-                                                        "VUID-vkDestroyImage-image-01000");
+    if (image_state) {
+        skip |= ValidateObjectNotInUse(device_data, image_state, obj_struct, "vkDestroyImage", "VUID-vkDestroyImage-image-01000");
     }
     return skip;
 }
 
-void PreCallRecordDestroyImage(layer_data *device_data, VkImage image, IMAGE_STATE *image_state, VK_OBJECT obj_struct) {
-    core_validation::InvalidateCommandBuffers(device_data, image_state->cb_bindings, obj_struct);
+void CoreChecks::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!image) return;
+    IMAGE_STATE *image_state = GetImageState(image);
+    VK_OBJECT obj_struct = {HandleToUint64(image), kVulkanObjectTypeImage};
+    InvalidateCommandBuffers(device_data, image_state->cb_bindings, obj_struct);
     // Clean up memory mapping, bindings and range references for image
     for (auto mem_binding : image_state->GetBoundMemory()) {
-        auto mem_info = core_validation::GetMemObjInfo(device_data, mem_binding);
+        auto mem_info = GetMemObjInfo(mem_binding);
         if (mem_info) {
-            core_validation::RemoveImageMemoryRange(obj_struct.handle, mem_info);
+            RemoveImageMemoryRange(obj_struct.handle, mem_info);
         }
     }
-    core_validation::ClearMemoryObjectBindings(device_data, obj_struct.handle, kVulkanObjectTypeImage);
+    ClearMemoryObjectBindings(obj_struct.handle, kVulkanObjectTypeImage);
     EraseQFOReleaseBarriers<VkImageMemoryBarrier>(device_data, image);
     // Remove image from imageMap
-    core_validation::GetImageMap(device_data)->erase(image);
-    std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *imageSubresourceMap =
-        core_validation::GetImageSubresourceMap(device_data);
+    GetImageMap()->erase(image);
+    std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *imageSubresourceMap = GetImageSubresourceMap();
 
     const auto &sub_entry = imageSubresourceMap->find(image);
     if (sub_entry != imageSubresourceMap->end()) {
         for (const auto &pair : sub_entry->second) {
-            core_validation::GetImageLayoutMap(device_data)->erase(pair);
+            GetImageLayoutMap()->erase(pair);
         }
         imageSubresourceMap->erase(sub_entry);
     }
 }
 
-bool ValidateImageAttributes(layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range) {
+bool CoreChecks::ValidateImageAttributes(layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
     if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
         char const str[] = "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT";
@@ -1373,10 +1587,9 @@
     return array_layer_count;
 }
 
-bool VerifyClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state,
-                            VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name) {
+bool CoreChecks::VerifyClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state,
+                                        VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
     uint32_t level_count = ResolveRemainingLevels(&range, image_state->createInfo.mipLevels);
     uint32_t layer_count = ResolveRemainingLayers(&range, image_state->createInfo.arrayLayers);
@@ -1390,7 +1603,7 @@
                                 "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
             }
         } else if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR == dest_image_layout) {
-            if (!GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image) {
+            if (!GetDeviceExtensions()->vk_khr_shared_presentable_image) {
                 // TODO: Add unique error id when available.
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 HandleToUint64(image_state->image), 0,
@@ -1407,7 +1620,7 @@
                 }
             }
         } else {
-            std::string error_code = "VUID-vkCmdClearColorImage-imageLayout-00005";
+            const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00005";
             if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
                 error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00012";
             } else {
@@ -1428,7 +1641,7 @@
             IMAGE_CMD_BUF_LAYOUT_NODE node;
             if (FindCmdBufLayout(device_data, cb_node, image_state->image, sub, node)) {
                 if (node.layout != dest_image_layout) {
-                    std::string error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
+                    const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
                     if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
                         error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
                     } else {
@@ -1446,9 +1659,9 @@
     return skip;
 }
 
-void RecordClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
-                            VkImageLayout dest_image_layout) {
-    VkImageCreateInfo *image_create_info = &(GetImageState(device_data, image)->createInfo);
+void CoreChecks::RecordClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image,
+                                        VkImageSubresourceRange range, VkImageLayout dest_image_layout) {
+    VkImageCreateInfo *image_create_info = &(GetImageState(image)->createInfo);
     uint32_t level_count = ResolveRemainingLevels(&range, image_create_info->mipLevels);
     uint32_t layer_count = ResolveRemainingLayers(&range, image_create_info->arrayLayers);
 
@@ -1465,63 +1678,68 @@
     }
 }
 
-bool PreCallValidateCmdClearColorImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                       VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
+bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                   const VkClearColorValue *pColor, uint32_t rangeCount,
+                                                   const VkImageSubresourceRange *pRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+
     bool skip = false;
     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    auto image_state = GetImageState(dev_data, image);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto image_state = GetImageState(image);
     if (cb_node && image_state) {
-        skip |=
-            ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-image-00003");
-        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdClearColorImage()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+        skip |= ValidateMemoryIsBoundToImage(device_data, image_state, "vkCmdClearColorImage()",
+                                             "VUID-vkCmdClearColorImage-image-00003");
+        skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdClearColorImage()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                       "VUID-vkCmdClearColorImage-commandBuffer-cmdpool");
-        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
-        if (GetApiVersion(dev_data) >= VK_API_VERSION_1_1 || GetDeviceExtensions(dev_data)->vk_khr_maintenance1) {
-            skip |=
-                ValidateImageFormatFeatureFlags(dev_data, image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearColorImage",
-                                                "VUID-vkCmdClearColorImage-image-01993", "VUID-vkCmdClearColorImage-image-01993");
+        skip |= ValidateCmd(device_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
+        if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
+            skip |= ValidateImageFormatFeatureFlags(device_data, image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
+                                                    "vkCmdClearColorImage", "VUID-vkCmdClearColorImage-image-01993",
+                                                    "VUID-vkCmdClearColorImage-image-01993");
         }
-        skip |= InsideRenderPass(dev_data, cb_node, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-renderpass");
+        skip |= InsideRenderPass(device_data, cb_node, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-renderpass");
         for (uint32_t i = 0; i < rangeCount; ++i) {
             std::string param_name = "pRanges[" + std::to_string(i) + "]";
-            skip |= ValidateCmdClearColorSubresourceRange(dev_data, image_state, pRanges[i], param_name.c_str());
-            skip |= ValidateImageAttributes(dev_data, image_state, pRanges[i]);
-            skip |= VerifyClearImageLayout(dev_data, cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearColorImage()");
+            skip |= ValidateCmdClearColorSubresourceRange(device_data, image_state, pRanges[i], param_name.c_str());
+            skip |= ValidateImageAttributes(device_data, image_state, pRanges[i]);
+            skip |= VerifyClearImageLayout(device_data, cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearColorImage()");
         }
     }
     return skip;
 }
 
-// This state recording routine is shared between ClearColorImage and ClearDepthStencilImage
-void PreCallRecordCmdClearImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
-                                uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    auto image_state = GetImageState(dev_data, image);
+void CoreChecks::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                 const VkClearColorValue *pColor, uint32_t rangeCount,
+                                                 const VkImageSubresourceRange *pRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+
+    auto cb_node = GetCBNode(commandBuffer);
+    auto image_state = GetImageState(image);
     if (cb_node && image_state) {
-        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
+        AddCommandBufferBindingImage(device_data, cb_node, image_state);
         for (uint32_t i = 0; i < rangeCount; ++i) {
-            RecordClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout);
+            RecordClearImageLayout(device_data, cb_node, image, pRanges[i], imageLayout);
         }
     }
 }
 
-bool PreCallValidateCmdClearDepthStencilImage(layer_data *device_data, VkCommandBuffer commandBuffer, VkImage image,
-                                              VkImageLayout imageLayout, uint32_t rangeCount,
-                                              const VkImageSubresourceRange *pRanges) {
+bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                          const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
+                                                          const VkImageSubresourceRange *pRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto image_state = GetImageState(device_data, image);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto image_state = GetImageState(image);
     if (cb_node && image_state) {
         skip |= ValidateMemoryIsBoundToImage(device_data, image_state, "vkCmdClearDepthStencilImage()",
                                              "VUID-vkCmdClearDepthStencilImage-image-00010");
         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdClearDepthStencilImage()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool");
         skip |= ValidateCmd(device_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
-        if (GetApiVersion(device_data) >= VK_API_VERSION_1_1 || GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+        if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
             skip |= ValidateImageFormatFeatureFlags(device_data, image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
                                                     "vkCmdClearDepthStencilImage", "VUID-vkCmdClearDepthStencilImage-image-01994",
                                                     "VUID-vkCmdClearDepthStencilImage-image-01994");
@@ -1559,6 +1777,21 @@
     return skip;
 }
 
+void CoreChecks::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                        const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
+                                                        const VkImageSubresourceRange *pRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+
+    auto cb_node = GetCBNode(commandBuffer);
+    auto image_state = GetImageState(image);
+    if (cb_node && image_state) {
+        AddCommandBufferBindingImage(device_data, cb_node, image_state);
+        for (uint32_t i = 0; i < rangeCount; ++i) {
+            RecordClearImageLayout(device_data, cb_node, image, pRanges[i], imageLayout);
+        }
+    }
+}
+
 // Returns true if [x, xoffset] and [y, yoffset] overlap
 static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
     bool result = false;
@@ -1640,12 +1873,12 @@
 VkExtent3D GetAdjustedDestImageExtent(VkFormat src_format, VkFormat dst_format, VkExtent3D extent) {
     VkExtent3D adjusted_extent = extent;
     if ((FormatIsCompressed(src_format) && (!FormatIsCompressed(dst_format)))) {
-        VkExtent3D block_size = FormatCompressedTexelBlockExtent(src_format);
+        VkExtent3D block_size = FormatTexelBlockExtent(src_format);
         adjusted_extent.width /= block_size.width;
         adjusted_extent.height /= block_size.height;
         adjusted_extent.depth /= block_size.depth;
     } else if ((!FormatIsCompressed(src_format) && (FormatIsCompressed(dst_format)))) {
-        VkExtent3D block_size = FormatCompressedTexelBlockExtent(dst_format);
+        VkExtent3D block_size = FormatTexelBlockExtent(dst_format);
         adjusted_extent.width *= block_size.width;
         adjusted_extent.height *= block_size.height;
         adjusted_extent.depth *= block_size.depth;
@@ -1665,6 +1898,13 @@
     // Don't allow mip adjustment to create 0 dim, but pass along a 0 if that's what subresource specified
     VkExtent3D extent = img->createInfo.extent;
 
+    // If multi-plane, adjust per-plane extent
+    if (FormatIsMultiplane(img->createInfo.format)) {
+        VkExtent2D divisors = FindMultiplaneExtentDivisors(img->createInfo.format, subresource->aspectMask);
+        extent.width /= divisors.width;
+        extent.height /= divisors.height;
+    }
+
     if (img->createInfo.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) {
         extent.width = (0 == extent.width ? 0 : std::max(2U, 1 + ((extent.width - 1) >> mip)));
         extent.height = (0 == extent.height ? 0 : std::max(2U, 1 + ((extent.height - 1) >> mip)));
@@ -1694,15 +1934,14 @@
 }
 
 // Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
-static inline VkExtent3D GetScaledItg(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img) {
+VkExtent3D CoreChecks::GetScaledItg(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img) {
     // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
     VkExtent3D granularity = {0, 0, 0};
-    auto pPool = GetCommandPoolNode(device_data, cb_node->createInfo.commandPool);
+    auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
     if (pPool) {
-        granularity =
-            GetPhysDevProperties(device_data)->queue_family_properties[pPool->queueFamilyIndex].minImageTransferGranularity;
+        granularity = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].minImageTransferGranularity;
         if (FormatIsCompressed(img->createInfo.format)) {
-            auto block_size = FormatCompressedTexelBlockExtent(img->createInfo.format);
+            auto block_size = FormatTexelBlockExtent(img->createInfo.format);
             granularity.width *= block_size.width;
             granularity.height *= block_size.height;
         }
@@ -1721,10 +1960,9 @@
 }
 
 // Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
-static inline bool CheckItgOffset(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkOffset3D *offset,
-                                  const VkExtent3D *granularity, const uint32_t i, const char *function, const char *member,
-                                  std::string vuid) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::CheckItgOffset(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkOffset3D *offset,
+                                const VkExtent3D *granularity, const uint32_t i, const char *function, const char *member,
+                                const char *vuid) {
     bool skip = false;
     VkExtent3D offset_extent = {};
     offset_extent.width = static_cast<uint32_t>(abs(offset->x));
@@ -1755,11 +1993,10 @@
 }
 
 // Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
-static inline bool CheckItgExtent(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkExtent3D *extent,
-                                  const VkOffset3D *offset, const VkExtent3D *granularity, const VkExtent3D *subresource_extent,
-                                  const VkImageType image_type, const uint32_t i, const char *function, const char *member,
-                                  std::string vuid) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::CheckItgExtent(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkExtent3D *extent,
+                                const VkOffset3D *offset, const VkExtent3D *granularity, const VkExtent3D *subresource_extent,
+                                const VkImageType image_type, const uint32_t i, const char *function, const char *member,
+                                const char *vuid) {
     bool skip = false;
     if (IsExtentAllZeroes(granularity)) {
         // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
@@ -1814,39 +2051,39 @@
     return skip;
 }
 
-bool ValidateImageMipLevel(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img, uint32_t mip_level,
-                           const uint32_t i, const char *function, const char *member, const std::string &vuid) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateImageMipLevel(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
+                                       uint32_t mip_level, const uint32_t i, const char *function, const char *member,
+                                       const char *vuid) {
     bool skip = false;
     if (mip_level >= img->createInfo.mipLevels) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_node->commandBuffer), vuid,
-                        "In %s, pRegions[%u].%s.mipLevel is %u, but provided image %" PRIx64 " has %u mip levels.", function, i,
-                        member, mip_level, HandleToUint64(img->image), img->createInfo.mipLevels);
+                        "In %s, pRegions[%u].%s.mipLevel is %u, but provided image %s has %u mip levels.", function, i, member,
+                        mip_level, report_data->FormatHandle(img->image).c_str(), img->createInfo.mipLevels);
     }
     return skip;
 }
 
-bool ValidateImageArrayLayerRange(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
-                                  const uint32_t base_layer, const uint32_t layer_count, const uint32_t i, const char *function,
-                                  const char *member, const std::string &vuid) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateImageArrayLayerRange(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
+                                              const uint32_t base_layer, const uint32_t layer_count, const uint32_t i,
+                                              const char *function, const char *member, const char *vuid) {
     bool skip = false;
     if (base_layer >= img->createInfo.arrayLayers || layer_count > img->createInfo.arrayLayers ||
         (base_layer + layer_count) > img->createInfo.arrayLayers) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_node->commandBuffer), vuid,
                         "In %s, pRegions[%u].%s.baseArrayLayer is %u and .layerCount is "
-                        "%u, but provided image %" PRIx64 " has %u array layers.",
-                        function, i, member, base_layer, layer_count, HandleToUint64(img->image), img->createInfo.arrayLayers);
+                        "%u, but provided image %s has %u array layers.",
+                        function, i, member, base_layer, layer_count, report_data->FormatHandle(img->image).c_str(),
+                        img->createInfo.arrayLayers);
     }
     return skip;
 }
 
 // Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy structure
-bool ValidateCopyBufferImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
-                                                            const IMAGE_STATE *img, const VkBufferImageCopy *region,
-                                                            const uint32_t i, const char *function, const std::string &vuid) {
+bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
+                                                                        const IMAGE_STATE *img, const VkBufferImageCopy *region,
+                                                                        const uint32_t i, const char *function, const char *vuid) {
     bool skip = false;
     VkExtent3D granularity = GetScaledItg(device_data, cb_node, img);
     skip |= CheckItgOffset(device_data, cb_node, &region->imageOffset, &granularity, i, function, "imageOffset", vuid);
@@ -1857,9 +2094,10 @@
 }
 
 // Check valid usage Image Transfer Granularity requirements for elements of a VkImageCopy structure
-bool ValidateCopyImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
-                                                      const IMAGE_STATE *src_img, const IMAGE_STATE *dst_img,
-                                                      const VkImageCopy *region, const uint32_t i, const char *function) {
+bool CoreChecks::ValidateCopyImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
+                                                                  const IMAGE_STATE *src_img, const IMAGE_STATE *dst_img,
+                                                                  const VkImageCopy *region, const uint32_t i,
+                                                                  const char *function) {
     bool skip = false;
     // Source image checks
     VkExtent3D granularity = GetScaledItg(device_data, cb_node, src_img);
@@ -1884,8 +2122,9 @@
 }
 
 // Validate contents of a VkImageCopy struct
-bool ValidateImageCopyData(const layer_data *device_data, const debug_report_data *report_data, const uint32_t regionCount,
-                           const VkImageCopy *ic_regions, const IMAGE_STATE *src_state, const IMAGE_STATE *dst_state) {
+bool CoreChecks::ValidateImageCopyData(const layer_data *device_data, const debug_report_data *report_data,
+                                       const uint32_t regionCount, const VkImageCopy *ic_regions, const IMAGE_STATE *src_state,
+                                       const IMAGE_STATE *dst_state) {
     bool skip = false;
 
     for (uint32_t i = 0; i < regionCount; i++) {
@@ -1938,7 +2177,7 @@
                             region.srcOffset.z);
         }
 
-        if (GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+        if (GetDeviceExtensions()->vk_khr_maintenance1) {
             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
                 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
                     skip |=
@@ -1963,15 +2202,15 @@
         }
 
         // Source checks that apply only to compressed images (or to _422 images if ycbcr enabled)
-        bool ext_ycbcr = GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion;
+        bool ext_ycbcr = GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion;
         if (FormatIsCompressed(src_state->createInfo.format) ||
             (ext_ycbcr && FormatIsSinglePlane_422(src_state->createInfo.format))) {
-            const VkExtent3D block_size = FormatCompressedTexelBlockExtent(src_state->createInfo.format);
+            const VkExtent3D block_size = FormatTexelBlockExtent(src_state->createInfo.format);
             //  image offsets must be multiples of block dimensions
             if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) ||
                 (SafeModulo(region.srcOffset.y, block_size.height) != 0) ||
                 (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01727" : "VUID-VkImageCopy-srcOffset-00157";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01727" : "VUID-VkImageCopy-srcOffset-00157";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 HandleToUint64(src_state->image), vuid,
                                 "vkCmdCopyImage(): pRegion[%d] srcOffset (%d, %d) must be multiples of the compressed image's "
@@ -1982,7 +2221,7 @@
             const VkExtent3D mip_extent = GetImageSubresourceExtent(src_state, &(region.srcSubresource));
             if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) &&
                 (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01728" : "VUID-VkImageCopy-extent-00158";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01728" : "VUID-VkImageCopy-extent-00158";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(src_state->image), vuid,
@@ -1994,7 +2233,7 @@
             // Extent height must be a multiple of block height, or extent+offset height must equal subresource height
             if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) &&
                 (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01729" : "VUID-VkImageCopy-extent-00159";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01729" : "VUID-VkImageCopy-extent-00159";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(src_state->image), vuid,
@@ -2006,7 +2245,7 @@
             // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
             uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth);
             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01730" : "VUID-VkImageCopy-extent-00160";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01730" : "VUID-VkImageCopy-extent-00160";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(src_state->image), vuid,
@@ -2055,7 +2294,7 @@
             }
         }
         // VU01199 changed with mnt1
-        if (GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+        if (GetDeviceExtensions()->vk_khr_maintenance1) {
             if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
                 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
                     skip |=
@@ -2082,13 +2321,13 @@
         // Dest checks that apply only to compressed images (or to _422 images if ycbcr enabled)
         if (FormatIsCompressed(dst_state->createInfo.format) ||
             (ext_ycbcr && FormatIsSinglePlane_422(dst_state->createInfo.format))) {
-            const VkExtent3D block_size = FormatCompressedTexelBlockExtent(dst_state->createInfo.format);
+            const VkExtent3D block_size = FormatTexelBlockExtent(dst_state->createInfo.format);
 
             //  image offsets must be multiples of block dimensions
             if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) ||
                 (SafeModulo(region.dstOffset.y, block_size.height) != 0) ||
                 (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01731" : "VUID-VkImageCopy-dstOffset-00162";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01731" : "VUID-VkImageCopy-dstOffset-00162";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 HandleToUint64(dst_state->image), vuid,
                                 "vkCmdCopyImage(): pRegion[%d] dstOffset (%d, %d) must be multiples of the compressed image's "
@@ -2099,7 +2338,7 @@
             const VkExtent3D mip_extent = GetImageSubresourceExtent(dst_state, &(region.dstSubresource));
             if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) &&
                 (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01732" : "VUID-VkImageCopy-extent-00163";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01732" : "VUID-VkImageCopy-extent-00163";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(dst_state->image), vuid,
@@ -2111,7 +2350,7 @@
             // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height
             if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) &&
                 (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01733" : "VUID-VkImageCopy-extent-00164";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01733" : "VUID-VkImageCopy-extent-00164";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 HandleToUint64(dst_state->image), vuid,
                                 "vkCmdCopyImage(): pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed "
@@ -2123,7 +2362,7 @@
             // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth
             uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth);
             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) {
-                std::string vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01734" : "VUID-VkImageCopy-extent-00165";
+                const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01734" : "VUID-VkImageCopy-extent-00165";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(dst_state->image), vuid,
@@ -2137,17 +2376,17 @@
 }
 
 // vkCmdCopyImage checks that only apply if the multiplane extension is enabled
-bool CopyImageMultiplaneValidation(const layer_data *dev_data, VkCommandBuffer command_buffer, const IMAGE_STATE *src_image_state,
-                                   const IMAGE_STATE *dst_image_state, const VkImageCopy region) {
+bool CoreChecks::CopyImageMultiplaneValidation(const layer_data *dev_data, VkCommandBuffer command_buffer,
+                                               const IMAGE_STATE *src_image_state, const IMAGE_STATE *dst_image_state,
+                                               const VkImageCopy region) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(dev_data);
 
     // Neither image is multiplane
     if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format))) {
         // If neither image is multi-plane the aspectMask member of src and dst must match
         if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Copy between non-multiplane images with differing aspectMasks ( 0x" << std::hex
+            ss << "vkCmdCopyImage(): Copy between non-multiplane images with differing aspectMasks ( 0x" << std::hex
                << region.srcSubresource.aspectMask << " and 0x" << region.dstSubresource.aspectMask << " )";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01551", "%s.", ss.str().c_str());
@@ -2158,14 +2397,14 @@
         VkImageAspectFlags aspect = region.srcSubresource.aspectMask;
         if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
+            ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01552", "%s.", ss.str().c_str());
         }
         if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
             (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
+            ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01553", "%s.", ss.str().c_str());
         }
@@ -2173,7 +2412,7 @@
         if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (FormatIsMultiplane(dst_image_state->createInfo.format)) &&
             (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Source image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
+            ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01557", "%s.", ss.str().c_str());
         }
@@ -2183,14 +2422,14 @@
         aspect = region.dstSubresource.aspectMask;
         if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
+            ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01554", "%s.", ss.str().c_str());
         }
         if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
             (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
+            ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01555", "%s.", ss.str().c_str());
         }
@@ -2198,7 +2437,7 @@
         if ((FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format)) &&
             (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: Dest image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
+            ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01556", "%s.", ss.str().c_str());
         }
@@ -2207,17 +2446,21 @@
     return skip;
 }
 
-bool PreCallValidateCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                 IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions,
-                                 VkImageLayout src_image_layout, VkImageLayout dst_image_layout) {
+bool CoreChecks::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                             VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                             const VkImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
-    skip = ValidateImageCopyData(device_data, report_data, region_count, regions, src_image_state, dst_image_state);
+
+    skip = ValidateImageCopyData(device_data, report_data, regionCount, pRegions, src_image_state, dst_image_state);
 
     VkCommandBuffer command_buffer = cb_node->commandBuffer;
 
-    for (uint32_t i = 0; i < region_count; i++) {
-        const VkImageCopy region = regions[i];
+    for (uint32_t i = 0; i < regionCount; i++) {
+        const VkImageCopy region = pRegions[i];
 
         // For comp/uncomp copies, the copy extent for the dest image must be adjusted
         VkExtent3D src_copy_extent = region.extent;
@@ -2252,7 +2495,7 @@
                                              region.dstSubresource.layerCount, i, "vkCmdCopyImage", "dstSubresource",
                                              "VUID-vkCmdCopyImage-dstSubresource-01699");
 
-        if (GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+        if (GetDeviceExtensions()->vk_khr_maintenance1) {
             // No chance of mismatch if we're overriding depth slice count
             if (!slice_override) {
                 // The number of depth slices in srcSubresource and dstSubresource must match
@@ -2265,7 +2508,7 @@
                                                                                : region.dstSubresource.layerCount);
                 if (src_slices != dst_slices) {
                     std::stringstream ss;
-                    ss << "vkCmdCopyImage: number of depth slices in source and destination subresources for pRegions[" << i
+                    ss << "vkCmdCopyImage(): number of depth slices in source and destination subresources for pRegions[" << i
                        << "] do not match";
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                     HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
@@ -2275,7 +2518,7 @@
             // For each region the layerCount member of srcSubresource and dstSubresource must match
             if (region.srcSubresource.layerCount != region.dstSubresource.layerCount) {
                 std::stringstream ss;
-                ss << "vkCmdCopyImage: number of layers in source and destination subresources for pRegions[" << i
+                ss << "vkCmdCopyImage(): number of layers in source and destination subresources for pRegions[" << i
                    << "] do not match";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
@@ -2283,14 +2526,14 @@
         }
 
         // Do multiplane-specific checks, if extension enabled
-        if (GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+        if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
             skip |= CopyImageMultiplaneValidation(device_data, command_buffer, src_image_state, dst_image_state, region);
         }
 
-        if (!GetDeviceExtensions(device_data)->vk_khr_sampler_ycbcr_conversion) {
+        if (!GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
             // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match
             if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
-                char const str[] = "vkCmdCopyImage: Src and dest aspectMasks for each region must match";
+                char const str[] = "vkCmdCopyImage(): Src and dest aspectMasks for each region must match";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00137", "%s.", str);
             }
@@ -2299,7 +2542,7 @@
         // For each region, the aspectMask member of srcSubresource must be present in the source image
         if (!VerifyAspectsPresent(region.srcSubresource.aspectMask, src_image_state->createInfo.format)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: pRegion[" << i
+            ss << "vkCmdCopyImage(): pRegion[" << i
                << "] srcSubresource.aspectMask cannot specify aspects not present in source image";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00142", "%s.", ss.str().c_str());
@@ -2308,7 +2551,8 @@
         // For each region, the aspectMask member of dstSubresource must be present in the destination image
         if (!VerifyAspectsPresent(region.dstSubresource.aspectMask, dst_image_state->createInfo.format)) {
             std::stringstream ss;
-            ss << "vkCmdCopyImage: pRegion[" << i << "] dstSubresource.aspectMask cannot specify aspects not present in dest image";
+            ss << "vkCmdCopyImage(): pRegion[" << i
+               << "] dstSubresource.aspectMask cannot specify aspects not present in dest image";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00143", "%s.", ss.str().c_str());
         }
@@ -2319,7 +2563,7 @@
             VkExtent3D img_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
             if (0 != ExceedsBounds(&region.srcOffset, &src_copy_extent, &img_extent)) {
                 std::stringstream ss;
-                ss << "vkCmdCopyImage: Source pRegion[" << i << "] with mipLevel [ " << region.srcSubresource.mipLevel
+                ss << "vkCmdCopyImage(): Source pRegion[" << i << "] with mipLevel [ " << region.srcSubresource.mipLevel
                    << " ], offset [ " << region.srcOffset.x << ", " << region.srcOffset.y << ", " << region.srcOffset.z
                    << " ], extent [ " << src_copy_extent.width << ", " << src_copy_extent.height << ", " << src_copy_extent.depth
                    << " ] exceeds the source image dimensions";
@@ -2331,7 +2575,7 @@
             img_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
             if (0 != ExceedsBounds(&region.dstOffset, &dst_copy_extent, &img_extent)) {
                 std::stringstream ss;
-                ss << "vkCmdCopyImage: Dest pRegion[" << i << "] with mipLevel [ " << region.dstSubresource.mipLevel
+                ss << "vkCmdCopyImage(): Dest pRegion[" << i << "] with mipLevel [ " << region.dstSubresource.mipLevel
                    << " ], offset [ " << region.dstOffset.x << ", " << region.dstOffset.y << ", " << region.dstOffset.z
                    << " ], extent [ " << dst_copy_extent.width << ", " << dst_copy_extent.height << ", " << dst_copy_extent.depth
                    << " ] exceeds the destination image dimensions";
@@ -2345,26 +2589,29 @@
         if (slice_override) src_copy_extent.depth = depth_slices;
         uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &src_copy_extent, &subresource_extent);
         if (extent_check & x_bit) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00144",
-                            "vkCmdCopyImage: Source image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
-                            "width [%1d].",
-                            i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00144",
+                        "vkCmdCopyImage(): Source image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                        "width [%1d].",
+                        i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
         }
 
         if (extent_check & y_bit) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00145",
-                            "vkCmdCopyImage: Source image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
-                            "height [%1d].",
-                            i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00145",
+                        "vkCmdCopyImage(): Source image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                        "height [%1d].",
+                        i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
         }
         if (extent_check & z_bit) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00147",
-                            "vkCmdCopyImage: Source image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
-                            "depth [%1d].",
-                            i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00147",
+                        "vkCmdCopyImage(): Source image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                        "depth [%1d].",
+                        i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
         }
 
         // Adjust dest extent if necessary
@@ -2375,21 +2622,21 @@
         if (extent_check & x_bit) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00150",
-                            "vkCmdCopyImage: Dest image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                            "vkCmdCopyImage(): Dest image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
                             "width [%1d].",
                             i, region.dstOffset.x, dst_copy_extent.width, subresource_extent.width);
         }
         if (extent_check & y_bit) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00151",
-                            "vkCmdCopyImage: Dest image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                            "vkCmdCopyImage(): Dest image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
                             "height [%1d].",
                             i, region.dstOffset.y, dst_copy_extent.height, subresource_extent.height);
         }
         if (extent_check & z_bit) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00153",
-                            "vkCmdCopyImage: Dest image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
+                            "vkCmdCopyImage(): Dest image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
                             "depth [%1d].",
                             i, region.dstOffset.z, dst_copy_extent.depth, subresource_extent.depth);
         }
@@ -2397,11 +2644,11 @@
         // The union of all source regions, and the union of all destination regions, specified by the elements of regions,
         // must not overlap in memory
         if (src_image_state->image == dst_image_state->image) {
-            for (uint32_t j = 0; j < region_count; j++) {
-                if (RegionIntersects(&region, &regions[j], src_image_state->createInfo.imageType,
+            for (uint32_t j = 0; j < regionCount; j++) {
+                if (RegionIntersects(&region, &pRegions[j], src_image_state->createInfo.imageType,
                                      FormatIsMultiplane(src_image_state->createInfo.format))) {
                     std::stringstream ss;
-                    ss << "vkCmdCopyImage: pRegions[" << i << "] src overlaps with pRegions[" << j << "].";
+                    ss << "vkCmdCopyImage(): pRegions[" << i << "] src overlaps with pRegions[" << j << "].";
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                     HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00124", "%s.", ss.str().c_str());
                 }
@@ -2419,7 +2666,7 @@
                             HandleToUint64(command_buffer), kVUID_Core_DrawState_MismatchedImageFormat, str);
         }
     } else {
-        if (!FormatSizesAreEqual(src_image_state->createInfo.format, dst_image_state->createInfo.format, region_count, regions)) {
+        if (!FormatSizesAreEqual(src_image_state->createInfo.format, dst_image_state->createInfo.format, regionCount, pRegions)) {
             char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes.";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-srcImage-00135", "%s.", str);
@@ -2440,7 +2687,7 @@
                                     "VUID-vkCmdCopyImage-srcImage-00126", "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
     skip |= ValidateImageUsageFlags(device_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
                                     "VUID-vkCmdCopyImage-dstImage-00131", "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
-    if (GetApiVersion(device_data) >= VK_API_VERSION_1_1 || GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+    if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
         skip |=
             ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, "vkCmdCopyImage()",
                                             "VUID-vkCmdCopyImage-srcImage-01995", "VUID-vkCmdCopyImage-srcImage-01995");
@@ -2454,35 +2701,40 @@
     skip |= ValidateCmd(device_data, cb_node, CMD_COPYIMAGE, "vkCmdCopyImage()");
     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-renderpass");
     bool hit_error = false;
-    const std::string invalid_src_layout_vuid =
-        (src_image_state->shared_presentable && core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+    const char *invalid_src_layout_vuid =
+        (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
             ? "VUID-vkCmdCopyImage-srcImageLayout-01917"
             : "VUID-vkCmdCopyImage-srcImageLayout-00129";
-    const std::string invalid_dst_layout_vuid =
-        (dst_image_state->shared_presentable && core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+    const char *invalid_dst_layout_vuid =
+        (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
             ? "VUID-vkCmdCopyImage-dstImageLayout-01395"
             : "VUID-vkCmdCopyImage-dstImageLayout-00134";
-    for (uint32_t i = 0; i < region_count; ++i) {
-        skip |= VerifyImageLayout(device_data, cb_node, src_image_state, regions[i].srcSubresource, src_image_layout,
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdCopyImage()", invalid_src_layout_vuid,
                                   "VUID-vkCmdCopyImage-srcImageLayout-00128", &hit_error);
-        skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, regions[i].dstSubresource, dst_image_layout,
+        skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdCopyImage()", invalid_dst_layout_vuid,
                                   "VUID-vkCmdCopyImage-dstImageLayout-00133", &hit_error);
         skip |= ValidateCopyImageTransferGranularityRequirements(device_data, cb_node, src_image_state, dst_image_state,
-                                                                 &regions[i], i, "vkCmdCopyImage()");
+                                                                 &pRegions[i], i, "vkCmdCopyImage()");
     }
 
     return skip;
 }
 
-void PreCallRecordCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                               IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions,
-                               VkImageLayout src_image_layout, VkImageLayout dst_image_layout) {
+void CoreChecks::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                           const VkImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
+
     // Make sure that all image slices are updated to correct layout
-    for (uint32_t i = 0; i < region_count; ++i) {
-        SetImageLayout(device_data, cb_node, src_image_state, regions[i].srcSubresource, src_image_layout);
-        SetImageLayout(device_data, cb_node, dst_image_state, regions[i].dstSubresource, dst_image_layout);
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
+        SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
     }
     // Update bindings between images and cmd buffer
     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
@@ -2497,10 +2749,48 @@
     return true;
 }
 
-bool PreCallValidateCmdClearAttachments(layer_data *device_data, VkCommandBuffer commandBuffer, uint32_t attachmentCount,
-                                        const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects) {
-    GLOBAL_CB_NODE *cb_node = GetCBNode(device_data, commandBuffer);
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateClearAttachmentExtent(layer_data *device_data, VkCommandBuffer command_buffer, uint32_t attachment_index,
+                                               FRAMEBUFFER_STATE *framebuffer, uint32_t fb_attachment, const VkRect2D &render_area,
+                                               uint32_t rect_count, const VkClearRect *clear_rects) {
+    bool skip = false;
+    const IMAGE_VIEW_STATE *image_view_state = nullptr;
+    if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < framebuffer->createInfo.attachmentCount)) {
+        image_view_state = GetImageViewState(framebuffer->createInfo.pAttachments[fb_attachment]);
+    }
+
+    for (uint32_t j = 0; j < rect_count; j++) {
+        if (!ContainsRect(render_area, clear_rects[j].rect)) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00016",
+                            "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
+                            "the current render pass instance.",
+                            j);
+        }
+
+        if (image_view_state) {
+            // The layers specified by a given element of pRects must be contained within every attachment that
+            // pAttachments refers to
+            const auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
+            if ((clear_rects[j].baseArrayLayer >= attachment_layer_count) ||
+                (clear_rects[j].baseArrayLayer + clear_rects[j].layerCount > attachment_layer_count)) {
+                skip |=
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00017",
+                            "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
+                            "of pAttachment[%d].",
+                            j, attachment_index);
+            }
+        }
+    }
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
+                                                    const VkClearAttachment *pAttachments, uint32_t rectCount,
+                                                    const VkClearRect *pRects) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+
+    GLOBAL_CB_NODE *cb_node = GetCBNode(commandBuffer);
 
     bool skip = false;
     if (cb_node) {
@@ -2513,12 +2803,12 @@
             // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
             // This warning should be made more specific. It'd be best to avoid triggering this test if it's a use that must call
             // CmdClearAttachments.
-            skip |= log_msg(
-                report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                HandleToUint64(commandBuffer), kVUID_Core_DrawState_ClearCmdBeforeDraw,
-                "vkCmdClearAttachments() issued on command buffer object 0x%" PRIx64
-                " prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
-                HandleToUint64(commandBuffer));
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), kVUID_Core_DrawState_ClearCmdBeforeDraw,
+                        "vkCmdClearAttachments() issued on command buffer object %s prior to any Draw Cmds. It is recommended you "
+                        "use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
+                        report_data->FormatHandle(commandBuffer).c_str());
         }
         skip |= OutsideRenderPass(device_data, cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass");
     }
@@ -2526,12 +2816,15 @@
     // Validate that attachment is in reference list of active subpass
     if (cb_node->activeRenderPass) {
         const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
+        const uint32_t renderpass_attachment_count = renderpass_create_info->attachmentCount;
         const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
-        auto framebuffer = GetFramebufferState(device_data, cb_node->activeFramebuffer);
+        auto framebuffer = GetFramebufferState(cb_node->activeFramebuffer);
+        const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea;
+        std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy;
 
-        for (uint32_t i = 0; i < attachmentCount; i++) {
-            auto clear_desc = &pAttachments[i];
-            VkImageView image_view = VK_NULL_HANDLE;
+        for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
+            auto clear_desc = &pAttachments[attachment_index];
+            uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
 
             if (0 == clear_desc->aspectMask) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -2540,34 +2833,47 @@
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00020", " ");
             } else if (clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
-                if (clear_desc->colorAttachment >= subpass_desc->colorAttachmentCount) {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-00015",
-                                    "vkCmdClearAttachments() color attachment index %d out of range for active subpass %d.",
-                                    clear_desc->colorAttachment, cb_node->activeSubpass);
-                } else if (subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment == VK_ATTACHMENT_UNUSED) {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
-                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer),
-                                    kVUID_Core_DrawState_MissingAttachmentReference,
-                                    "vkCmdClearAttachments() color attachment index %d is VK_ATTACHMENT_UNUSED; ignored.",
-                                    clear_desc->colorAttachment);
+                uint32_t color_attachment = VK_ATTACHMENT_UNUSED;
+                if (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount) {
+                    color_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
+                    if ((color_attachment != VK_ATTACHMENT_UNUSED) && (color_attachment >= renderpass_attachment_count)) {
+                        skip |= log_msg(
+                            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
+                            "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u is not VK_ATTACHMENT_UNUSED "
+                            "and not a valid attachment for render pass %s attachmentCount=%u. Subpass %u pColorAttachment[%u]=%u.",
+                            attachment_index, clear_desc->colorAttachment,
+                            report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(), cb_node->activeSubpass,
+                            clear_desc->colorAttachment, color_attachment, renderpass_attachment_count);
+
+                        color_attachment = VK_ATTACHMENT_UNUSED;  // Defensive, prevent lookup past end of renderpass attachment
+                    }
                 } else {
-                    image_view = framebuffer->createInfo
-                                     .pAttachments[subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment];
+                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                    HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
+                                    "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u out of range for render pass %s"
+                                    " subpass %u. colorAttachmentCount=%u",
+                                    attachment_index, clear_desc->colorAttachment,
+                                    report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(),
+                                    cb_node->activeSubpass, subpass_desc->colorAttachmentCount);
                 }
+                fb_attachment = color_attachment;
+
                 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
                     (clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
                     char const str[] =
                         "vkCmdClearAttachments() aspectMask [%d] must set only VK_IMAGE_ASPECT_COLOR_BIT of a color attachment.";
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00019", str, i);
+                    skip |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00019", str, attachment_index);
                 }
             } else {  // Must be depth and/or stencil
                 if (((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
                     ((clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) {
                     char const str[] = "vkCmdClearAttachments() aspectMask [%d] is not a valid combination of bits.";
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-parameter", str, i);
+                                    HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-parameter", str,
+                                    attachment_index);
                 }
                 if (!subpass_desc->pDepthStencilAttachment ||
                     (subpass_desc->pDepthStencilAttachment->attachment == VK_ATTACHMENT_UNUSED)) {
@@ -2576,60 +2882,47 @@
                         HandleToUint64(commandBuffer), kVUID_Core_DrawState_MissingAttachmentReference,
                         "vkCmdClearAttachments() depth/stencil clear with no depth/stencil attachment in subpass; ignored");
                 } else {
-                    image_view = framebuffer->createInfo.pAttachments[subpass_desc->pDepthStencilAttachment->attachment];
+                    fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
                 }
             }
-            if (image_view) {
-                auto image_view_state = GetImageViewState(device_data, image_view);
-                for (uint32_t j = 0; j < rectCount; j++) {
-                    // The rectangular region specified by a given element of pRects must be contained within the render area of
-                    // the current render pass instance
-                    if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
-                        if (false == ContainsRect(cb_node->activeRenderPassBeginInfo.renderArea, pRects[j].rect)) {
-                            skip |=
-                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                        HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-pRects-00016",
-                                        "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
-                                        "the current render pass instance.",
-                                        j);
-                        }
-                    } else {
-                        const auto local_rect =
-                            pRects[j].rect;  // local copy of rect captured by value below to preserve original contents
-                        cb_node->cmd_execute_commands_functions.emplace_back([=](GLOBAL_CB_NODE *prim_cb, VkFramebuffer fb) {
-                            if (false == ContainsRect(prim_cb->activeRenderPassBeginInfo.renderArea, local_rect)) {
-                                return log_msg(
-                                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-pRects-00016",
-                                    "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
-                                    "the current render pass instance.",
-                                    j);
-                            }
-                            return false;
-                        });
-                    }
-                    // The layers specified by a given element of pRects must be contained within every attachment that
-                    // pAttachments refers to
-                    auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
-                    if ((pRects[j].baseArrayLayer >= attachment_layer_count) ||
-                        (pRects[j].baseArrayLayer + pRects[j].layerCount > attachment_layer_count)) {
-                        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                        HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-pRects-00017",
-                                        "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
-                                        "of pAttachment[%d].",
-                                        j, i);
-                    }
+            if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
+                skip |= ValidateClearAttachmentExtent(device_data, commandBuffer, attachment_index, framebuffer, fb_attachment,
+                                                      render_area, rectCount, pRects);
+            } else {
+                // if a secondary level command buffer inherits the framebuffer from the primary command buffer
+                // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
+                if (!clear_rect_copy) {
+                    // We need a copy of the clear rectangles that will persist until the last lambda executes
+                    // but we want to create it as lazily as possible
+                    clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
                 }
+
+                auto val_fn = [device_data, commandBuffer, attachment_index, fb_attachment, rectCount, clear_rect_copy](
+                                  GLOBAL_CB_NODE *prim_cb, VkFramebuffer fb) {
+                    assert(rectCount == clear_rect_copy->size());
+                    FRAMEBUFFER_STATE *framebuffer = device_data->GetFramebufferState(fb);
+                    const auto &render_area = prim_cb->activeRenderPassBeginInfo.renderArea;
+                    bool skip = false;
+                    skip =
+                        device_data->ValidateClearAttachmentExtent(device_data, commandBuffer, attachment_index, framebuffer,
+                                                                   fb_attachment, render_area, rectCount, clear_rect_copy->data());
+                    return skip;
+                };
+                cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
             }
         }
     }
     return skip;
 }
 
-bool PreCallValidateCmdResolveImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                    VkImageLayout src_image_layout, IMAGE_STATE *dst_image_state, VkImageLayout dst_image_layout,
-                                    uint32_t regionCount, const VkImageResolve *pRegions) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                                VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                const VkImageResolve *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
+
     bool skip = false;
     if (cb_node && src_image_state && dst_image_state) {
         skip |= ValidateMemoryIsBoundToImage(device_data, src_image_state, "vkCmdResolveImage()",
@@ -2645,14 +2938,12 @@
                                                 "VUID-vkCmdResolveImage-dstImage-02003");
 
         bool hit_error = false;
-        const std::string invalid_src_layout_vuid =
-            (src_image_state->shared_presentable &&
-             core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+        const char *invalid_src_layout_vuid =
+            (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
                 ? "VUID-vkCmdResolveImage-srcImageLayout-01400"
                 : "VUID-vkCmdResolveImage-srcImageLayout-00261";
-        const std::string invalid_dst_layout_vuid =
-            (dst_image_state->shared_presentable &&
-             core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+        const char *invalid_dst_layout_vuid =
+            (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
                 ? "VUID-vkCmdResolveImage-dstImageLayout-01401"
                 : "VUID-vkCmdResolveImage-dstImageLayout-00263";
         // For each region, the number of layers in the image subresource should not be zero
@@ -2662,10 +2953,10 @@
                                                    "srcSubresource", i);
             skip |= ValidateImageSubresourceLayers(device_data, cb_node, &pRegions[i].dstSubresource, "vkCmdResolveImage()",
                                                    "dstSubresource", i);
-            skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, src_image_layout,
+            skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdResolveImage()", invalid_src_layout_vuid,
                                       "VUID-vkCmdResolveImage-srcImageLayout-00260", &hit_error);
-            skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dst_image_layout,
+            skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdResolveImage()", invalid_dst_layout_vuid,
                                       "VUID-vkCmdResolveImage-dstImageLayout-00262", &hit_error);
             skip |= ValidateImageMipLevel(device_data, cb_node, src_image_state, pRegions[i].srcSubresource.mipLevel, i,
@@ -2684,13 +2975,13 @@
                 skip |= log_msg(
                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-layerCount-00267",
-                    "vkCmdResolveImage: layerCount in source and destination subresource of pRegions[%d] does not match.", i);
+                    "vkCmdResolveImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
             }
             // For each region, src and dest image aspect must be color only
             if ((pRegions[i].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
                 (pRegions[i].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
                 char const str[] =
-                    "vkCmdResolveImage: src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
+                    "vkCmdResolveImage(): src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-aspectMask-00266", "%s.", str);
             }
@@ -2722,17 +3013,26 @@
     return skip;
 }
 
-void PreCallRecordCmdResolveImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                  IMAGE_STATE *dst_image_state) {
+void CoreChecks::PreCallRecordCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                              VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                              const VkImageResolve *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
+
     // Update bindings between images and cmd buffer
     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
 }
 
-bool PreCallValidateCmdBlitImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                 IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageBlit *regions,
-                                 VkImageLayout src_image_layout, VkImageLayout dst_image_layout, VkFilter filter) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                             VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                             const VkImageBlit *pRegions, VkFilter filter) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
 
     bool skip = false;
     if (cb_node) {
@@ -2782,20 +3082,20 @@
         if ((VK_FILTER_CUBIC_IMG == filter) && (VK_IMAGE_TYPE_3D != src_type)) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-filter-00237",
-                            "vkCmdBlitImage: source image type must be VK_IMAGE_TYPE_3D when cubic filtering is specified.");
+                            "vkCmdBlitImage(): source image type must be VK_IMAGE_TYPE_3D when cubic filtering is specified.");
         }
 
         if ((VK_SAMPLE_COUNT_1_BIT != src_image_state->createInfo.samples) ||
             (VK_SAMPLE_COUNT_1_BIT != dst_image_state->createInfo.samples)) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00228",
-                            "vkCmdBlitImage: source or dest image has sample count other than VK_SAMPLE_COUNT_1_BIT.");
+                            "vkCmdBlitImage(): source or dest image has sample count other than VK_SAMPLE_COUNT_1_BIT.");
         }
 
         // Validate consistency for unsigned formats
         if (FormatIsUInt(src_format) != FormatIsUInt(dst_format)) {
             std::stringstream ss;
-            ss << "vkCmdBlitImage: If one of srcImage and dstImage images has unsigned integer format, "
+            ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has unsigned integer format, "
                << "the other one must also have unsigned integer format.  "
                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -2805,7 +3105,7 @@
         // Validate consistency for signed formats
         if (FormatIsSInt(src_format) != FormatIsSInt(dst_format)) {
             std::stringstream ss;
-            ss << "vkCmdBlitImage: If one of srcImage and dstImage images has signed integer format, "
+            ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has signed integer format, "
                << "the other one must also have signed integer format.  "
                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -2815,7 +3115,7 @@
         // Validate filter for Depth/Stencil formats
         if (FormatIsDepthOrStencil(src_format) && (filter != VK_FILTER_NEAREST)) {
             std::stringstream ss;
-            ss << "vkCmdBlitImage: If the format of srcImage is a depth, stencil, or depth stencil "
+            ss << "vkCmdBlitImage(): If the format of srcImage is a depth, stencil, or depth stencil "
                << "then filter must be VK_FILTER_NEAREST.";
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00232", "%s.", ss.str().c_str());
@@ -2825,7 +3125,7 @@
         if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
             if (src_format != dst_format) {
                 std::stringstream ss;
-                ss << "vkCmdBlitImage: If one of srcImage and dstImage images has a format of depth, stencil or depth "
+                ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has a format of depth, stencil or depth "
                    << "stencil, the other one must have exactly the same format.  "
                    << "Source format is " << string_VkFormat(src_format) << " Destination format is "
                    << string_VkFormat(dst_format);
@@ -2836,23 +3136,21 @@
         }  // Depth or Stencil
 
         // Do per-region checks
-        const std::string invalid_src_layout_vuid =
-            (src_image_state->shared_presentable &&
-             core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+        const char *invalid_src_layout_vuid =
+            (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
                 ? "VUID-vkCmdBlitImage-srcImageLayout-01398"
                 : "VUID-vkCmdBlitImage-srcImageLayout-00222";
-        const std::string invalid_dst_layout_vuid =
-            (dst_image_state->shared_presentable &&
-             core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+        const char *invalid_dst_layout_vuid =
+            (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
                 ? "VUID-vkCmdBlitImage-dstImageLayout-01399"
                 : "VUID-vkCmdBlitImage-dstImageLayout-00227";
-        for (uint32_t i = 0; i < region_count; i++) {
-            const VkImageBlit rgn = regions[i];
+        for (uint32_t i = 0; i < regionCount; i++) {
+            const VkImageBlit rgn = pRegions[i];
             bool hit_error = false;
-            skip |= VerifyImageLayout(device_data, cb_node, src_image_state, rgn.srcSubresource, src_image_layout,
+            skip |= VerifyImageLayout(device_data, cb_node, src_image_state, rgn.srcSubresource, srcImageLayout,
                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdBlitImage()", invalid_src_layout_vuid,
                                       "VUID-vkCmdBlitImage-srcImageLayout-00221", &hit_error);
-            skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, rgn.dstSubresource, dst_image_layout,
+            skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, rgn.dstSubresource, dstImageLayout,
                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdBlitImage()", invalid_dst_layout_vuid,
                                       "VUID-vkCmdBlitImage-dstImageLayout-00226", &hit_error);
             skip |=
@@ -2873,7 +3171,7 @@
             if ((rgn.srcOffsets[0].x == rgn.srcOffsets[1].x) || (rgn.srcOffsets[0].y == rgn.srcOffsets[1].y) ||
                 (rgn.srcOffsets[0].z == rgn.srcOffsets[1].z)) {
                 std::stringstream ss;
-                ss << "vkCmdBlitImage: pRegions[" << i << "].srcOffsets specify a zero-volume area.";
+                ss << "vkCmdBlitImage(): pRegions[" << i << "].srcOffsets specify a zero-volume area.";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
@@ -2881,7 +3179,7 @@
             if ((rgn.dstOffsets[0].x == rgn.dstOffsets[1].x) || (rgn.dstOffsets[0].y == rgn.dstOffsets[1].y) ||
                 (rgn.dstOffsets[0].z == rgn.dstOffsets[1].z)) {
                 std::stringstream ss;
-                ss << "vkCmdBlitImage: pRegions[" << i << "].dstOffsets specify a zero-volume area.";
+                ss << "vkCmdBlitImage(): pRegions[" << i << "].dstOffsets specify a zero-volume area.";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
@@ -2889,22 +3187,22 @@
 
             // Check that src/dst layercounts match
             if (rgn.srcSubresource.layerCount != rgn.dstSubresource.layerCount) {
-                skip |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-layerCount-00239",
-                            "vkCmdBlitImage: layerCount in source and destination subresource of pRegions[%d] does not match.", i);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-layerCount-00239",
+                    "vkCmdBlitImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
             }
 
             if (rgn.srcSubresource.aspectMask != rgn.dstSubresource.aspectMask) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00238",
-                                "vkCmdBlitImage: aspectMask members for pRegion[%d] do not match.", i);
+                                "vkCmdBlitImage(): aspectMask members for pRegion[%d] do not match.", i);
             }
 
             if (!VerifyAspectsPresent(rgn.srcSubresource.aspectMask, src_format)) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00241",
-                                "vkCmdBlitImage: region [%d] source aspectMask (0x%x) specifies aspects not present in source "
+                                "vkCmdBlitImage(): region [%d] source aspectMask (0x%x) specifies aspects not present in source "
                                 "image format %s.",
                                 i, rgn.srcSubresource.aspectMask, string_VkFormat(src_format));
             }
@@ -2913,19 +3211,20 @@
                 skip |= log_msg(
                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00242",
-                    "vkCmdBlitImage: region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.", i,
-                    rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
+                    "vkCmdBlitImage(): region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.",
+                    i, rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
             }
 
             // Validate source image offsets
             VkExtent3D src_extent = GetImageSubresourceExtent(src_image_state, &(rgn.srcSubresource));
             if (VK_IMAGE_TYPE_1D == src_type) {
                 if ((0 != rgn.srcOffsets[0].y) || (1 != rgn.srcOffsets[1].y)) {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00245",
-                                    "vkCmdBlitImage: region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
-                                    "of (%1d, %1d). These must be (0, 1).",
-                                    i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
+                    skip |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00245",
+                                "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
+                                "of (%1d, %1d). These must be (0, 1).",
+                                i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
                 }
             }
 
@@ -2933,7 +3232,7 @@
                 if ((0 != rgn.srcOffsets[0].z) || (1 != rgn.srcOffsets[1].z)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00247",
-                                    "vkCmdBlitImage: region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
+                                    "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
                                     "srcOffset[].z values of (%1d, %1d). These must be (0, 1).",
                                     i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z);
                 }
@@ -2943,11 +3242,11 @@
             if ((rgn.srcOffsets[0].x < 0) || (rgn.srcOffsets[0].x > static_cast<int32_t>(src_extent.width)) ||
                 (rgn.srcOffsets[1].x < 0) || (rgn.srcOffsets[1].x > static_cast<int32_t>(src_extent.width))) {
                 oob = true;
-                skip |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00243",
-                            "vkCmdBlitImage: region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).",
-                            i, rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00243",
+                    "vkCmdBlitImage(): region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).", i,
+                    rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
             }
             if ((rgn.srcOffsets[0].y < 0) || (rgn.srcOffsets[0].y > static_cast<int32_t>(src_extent.height)) ||
                 (rgn.srcOffsets[1].y < 0) || (rgn.srcOffsets[1].y > static_cast<int32_t>(src_extent.height))) {
@@ -2955,33 +3254,34 @@
                 skip |= log_msg(
                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00244",
-                    "vkCmdBlitImage: region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).", i,
+                    "vkCmdBlitImage(): region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).", i,
                     rgn.srcOffsets[0].y, rgn.srcOffsets[1].y, src_extent.height);
             }
             if ((rgn.srcOffsets[0].z < 0) || (rgn.srcOffsets[0].z > static_cast<int32_t>(src_extent.depth)) ||
                 (rgn.srcOffsets[1].z < 0) || (rgn.srcOffsets[1].z > static_cast<int32_t>(src_extent.depth))) {
                 oob = true;
-                skip |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00246",
-                            "vkCmdBlitImage: region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).",
-                            i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00246",
+                    "vkCmdBlitImage(): region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).", i,
+                    rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
             }
             if (oob) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00215",
-                                "vkCmdBlitImage: region [%d] source image blit region exceeds image dimensions.", i);
+                                "vkCmdBlitImage(): region [%d] source image blit region exceeds image dimensions.", i);
             }
 
             // Validate dest image offsets
             VkExtent3D dst_extent = GetImageSubresourceExtent(dst_image_state, &(rgn.dstSubresource));
             if (VK_IMAGE_TYPE_1D == dst_type) {
                 if ((0 != rgn.dstOffsets[0].y) || (1 != rgn.dstOffsets[1].y)) {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00250",
-                                    "vkCmdBlitImage: region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
-                                    "(%1d, %1d). These must be (0, 1).",
-                                    i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
+                    skip |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00250",
+                                "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
+                                "(%1d, %1d). These must be (0, 1).",
+                                i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
                 }
             }
 
@@ -2989,7 +3289,7 @@
                 if ((0 != rgn.dstOffsets[0].z) || (1 != rgn.dstOffsets[1].z)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00252",
-                                    "vkCmdBlitImage: region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
+                                    "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
                                     "dstOffset[].z values of (%1d, %1d). These must be (0, 1).",
                                     i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z);
                 }
@@ -2999,11 +3299,11 @@
             if ((rgn.dstOffsets[0].x < 0) || (rgn.dstOffsets[0].x > static_cast<int32_t>(dst_extent.width)) ||
                 (rgn.dstOffsets[1].x < 0) || (rgn.dstOffsets[1].x > static_cast<int32_t>(dst_extent.width))) {
                 oob = true;
-                skip |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00248",
-                            "vkCmdBlitImage: region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).",
-                            i, rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00248",
+                    "vkCmdBlitImage(): region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).", i,
+                    rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
             }
             if ((rgn.dstOffsets[0].y < 0) || (rgn.dstOffsets[0].y > static_cast<int32_t>(dst_extent.height)) ||
                 (rgn.dstOffsets[1].y < 0) || (rgn.dstOffsets[1].y > static_cast<int32_t>(dst_extent.height))) {
@@ -3011,32 +3311,33 @@
                 skip |= log_msg(
                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00249",
-                    "vkCmdBlitImage: region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).", i,
+                    "vkCmdBlitImage(): region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).", i,
                     rgn.dstOffsets[0].y, rgn.dstOffsets[1].y, dst_extent.height);
             }
             if ((rgn.dstOffsets[0].z < 0) || (rgn.dstOffsets[0].z > static_cast<int32_t>(dst_extent.depth)) ||
                 (rgn.dstOffsets[1].z < 0) || (rgn.dstOffsets[1].z > static_cast<int32_t>(dst_extent.depth))) {
                 oob = true;
-                skip |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00251",
-                            "vkCmdBlitImage: region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).",
-                            i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00251",
+                    "vkCmdBlitImage(): region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).", i,
+                    rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
             }
             if (oob) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                 HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00216",
-                                "vkCmdBlitImage: region [%d] destination image blit region exceeds image dimensions.", i);
+                                "vkCmdBlitImage(): region [%d] destination image blit region exceeds image dimensions.", i);
             }
 
             if ((VK_IMAGE_TYPE_3D == src_type) || (VK_IMAGE_TYPE_3D == dst_type)) {
                 if ((0 != rgn.srcSubresource.baseArrayLayer) || (1 != rgn.srcSubresource.layerCount) ||
                     (0 != rgn.dstSubresource.baseArrayLayer) || (1 != rgn.dstSubresource.layerCount)) {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00240",
-                                    "vkCmdBlitImage: region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
-                                    "layerCount other than 1.",
-                                    i);
+                    skip |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00240",
+                                "vkCmdBlitImage(): region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
+                                "layerCount other than 1.",
+                                i);
                 }
             }
         }  // per-region checks
@@ -3046,27 +3347,29 @@
     return skip;
 }
 
-void PreCallRecordCmdBlitImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                               IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageBlit *regions,
-                               VkImageLayout src_image_layout, VkImageLayout dst_image_layout) {
+void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                           const VkImageBlit *pRegions, VkFilter filter) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_image_state = GetImageState(dstImage);
+
     // Make sure that all image slices are updated to correct layout
-    for (uint32_t i = 0; i < region_count; ++i) {
-        SetImageLayout(device_data, cb_node, src_image_state, regions[i].srcSubresource, src_image_layout);
-        SetImageLayout(device_data, cb_node, dst_image_state, regions[i].dstSubresource, dst_image_layout);
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
+        SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
     }
     // Update bindings between images and cmd buffer
     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
 }
 
-// This validates that the initial layout specified in the command buffer for
-// the IMAGE is the same
-// as the global IMAGE layout
-bool ValidateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
-                                std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const &globalImageLayoutMap,
-                                std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &overlayLayoutMap) {
+// This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout
+bool CoreChecks::ValidateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
+                                            std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const &globalImageLayoutMap,
+                                            std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &overlayLayoutMap) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
     for (auto cb_image_data : pCB->imageLayoutMap) {
         VkImageLayout imageLayout;
 
@@ -3076,20 +3379,23 @@
                 // TODO: Set memory invalid which is in mem_tracker currently
             } else if (imageLayout != cb_image_data.second.initialLayout) {
                 if (cb_image_data.first.hasSubresource) {
+                    skip |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
+                                "Submitted command buffer expects image %s (subresource: aspectMask 0x%X array layer %u, mip level "
+                                "%u) to be in layout %s--instead, image %s's current layout is %s.",
+                                report_data->FormatHandle(cb_image_data.first.image).c_str(),
+                                cb_image_data.first.subresource.aspectMask, cb_image_data.first.subresource.arrayLayer,
+                                cb_image_data.first.subresource.mipLevel, string_VkImageLayout(cb_image_data.second.initialLayout),
+                                report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
+                } else {
                     skip |= log_msg(
                         report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
-                        "Cannot submit cmd buffer using image (0x%" PRIx64
-                        ") [sub-resource: aspectMask 0x%X array layer %u, mip level %u], with layout %s when first use is %s.",
-                        HandleToUint64(cb_image_data.first.image), cb_image_data.first.subresource.aspectMask,
-                        cb_image_data.first.subresource.arrayLayer, cb_image_data.first.subresource.mipLevel,
-                        string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout));
-                } else {
-                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                                    HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
-                                    "Cannot submit cmd buffer using image (0x%" PRIx64 ") with layout %s when first use is %s.",
-                                    HandleToUint64(cb_image_data.first.image), string_VkImageLayout(imageLayout),
-                                    string_VkImageLayout(cb_image_data.second.initialLayout));
+                        "Submitted command buffer expects image %s to be in layout %s--instead, image %s's current layout is %s.",
+                        report_data->FormatHandle(cb_image_data.first.image).c_str(),
+                        string_VkImageLayout(cb_image_data.second.initialLayout),
+                        report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
                 }
             }
             SetLayout(overlayLayoutMap, cb_image_data.first, cb_image_data.second.layout);
@@ -3098,7 +3404,7 @@
     return skip;
 }
 
-void UpdateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB) {
+void CoreChecks::UpdateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB) {
     for (auto cb_image_data : pCB->imageLayoutMap) {
         VkImageLayout imageLayout;
         FindGlobalLayout(device_data, cb_image_data.first, imageLayout);
@@ -3106,91 +3412,30 @@
     }
 }
 
-// Print readable FlagBits in FlagMask
-static std::string StringVkAccessFlags(VkAccessFlags accessMask) {
-    std::string result;
-    std::string separator;
-
-    if (accessMask == 0) {
-        result = "[None]";
-    } else {
-        result = "[";
-        for (auto i = 0; i < 32; i++) {
-            if (accessMask & (1 << i)) {
-                result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i));
-                separator = " | ";
-            }
-        }
-        result = result + "]";
-    }
-    return result;
-}
-
-#if 0  // This fxn seems vestigial, not called anywhere.  All VkAccessFlagBits VUIDs are implicit & being checked by parameter
-       // validation ToBeRemoved (disabled 6/18)
-
-// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set. If required_bit is zero, accessMask
-// must have at least one of 'optional_bits' set
-// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions
-static bool ValidateMaskBits(core_validation::layer_data *device_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
-                             const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits,
-                             const char *type) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
-    bool skip = false;
-
-    if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) {
-        if (accessMask & ~(required_bit | optional_bits)) {
-            // TODO: Verify against Valid Use
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cmdBuffer), kVUID_Core_DrawState_InvalidBarrier,
-                            "Additional bits in %s accessMask 0x%X %s are specified when layout is %s.", type, accessMask,
-                            StringVkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
-        }
-    } else {
-        if (!required_bit) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cmdBuffer), kVUID_Core_DrawState_InvalidBarrier,
-                            "%s AccessMask %d %s must contain at least one of access bits %d %s when layout is %s, unless the app "
-                            "has previously added a barrier for this transition.",
-                            type, accessMask, StringVkAccessFlags(accessMask).c_str(), optional_bits,
-                            StringVkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout));
-        } else {
-            std::string opt_bits;
-            if (optional_bits != 0) {
-                std::stringstream ss;
-                ss << optional_bits;
-                opt_bits = "and may have optional bits " + ss.str() + ' ' + StringVkAccessFlags(optional_bits);
-            }
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cmdBuffer), kVUID_Core_DrawState_InvalidBarrier,
-                            "%s AccessMask %d %s must have required access bit %d %s %s when layout is %s, unless the app has "
-                            "previously added a barrier for this transition.",
-                            type, accessMask, StringVkAccessFlags(accessMask).c_str(), required_bit,
-                            StringVkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout));
-        }
-    }
-    return skip;
-}
-#endif
-
 // ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
 // VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY
 // layout attachments don't have CLEAR as their loadOp.
-bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
-                                           const VkImageLayout first_layout, const uint32_t attachment,
-                                           const VkAttachmentDescription2KHR &attachment_description) {
+bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
+                                                       const VkImageLayout first_layout, const uint32_t attachment,
+                                                       const VkAttachmentDescription2KHR &attachment_description) {
     bool skip = false;
     const char *vuid;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
 
     // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
     if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
-        if ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
-            (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)) {
-            vuid =
-                use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053" : "VUID-VkRenderPassCreateInfo-pAttachments-00836";
+        if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
+                        (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
+                        (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL))) {
             skip |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522",
+                        "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
+        } else if (!use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
+                                (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkRenderPassCreateInfo-pAttachments-00836",
                         "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
         }
     }
@@ -3214,9 +3459,8 @@
     return skip;
 }
 
-bool ValidateLayouts(const core_validation::layer_data *device_data, RenderPassCreateVersion rp_version, VkDevice device,
-                     const VkRenderPassCreateInfo2KHR *pCreateInfo) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateLayouts(layer_data *device_data, RenderPassCreateVersion rp_version, VkDevice device,
+                                 const VkRenderPassCreateInfo2KHR *pCreateInfo) {
     bool skip = false;
     const char *vuid;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
@@ -3278,7 +3522,7 @@
 
                 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
                 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
-                    if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) {
+                    if (GetDeviceExtensions()->vk_khr_maintenance2) {
                         break;
                     } else {
                         // Intentionally fall through to generic error message
@@ -3351,13 +3595,14 @@
                                     string_VkImageLayout(subpass.pColorAttachments[j].layout));
             }
 
-            if (subpass.pResolveAttachments && (subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_UNDEFINED ||
-                                                subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_PREINITIALIZED)) {
+            if (subpass.pResolveAttachments && (subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) &&
+                (subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_UNDEFINED ||
+                 subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_PREINITIALIZED)) {
                 vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                                "Layout for color attachment reference %u in subpass %u is %s but should be "
+                                "Layout for resolve attachment reference %u in subpass %u is %s but should be "
                                 "COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
-                                j, i, string_VkImageLayout(subpass.pColorAttachments[j].layout));
+                                j, i, string_VkImageLayout(subpass.pResolveAttachments[j].layout));
             }
 
             if (attach_first_use[attach_index]) {
@@ -3393,7 +3638,7 @@
 
                 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
                 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
-                    if (GetDeviceExtensions(device_data)->vk_khr_maintenance2) {
+                    if (GetDeviceExtensions()->vk_khr_maintenance2) {
                         break;
                     } else {
                         // Intentionally fall through to generic error message
@@ -3421,9 +3666,8 @@
 }
 
 // For any image objects that overlap mapped memory, verify that their layouts are PREINIT or GENERAL
-bool ValidateMapImageLayouts(core_validation::layer_data *device_data, VkDevice device, DEVICE_MEM_INFO const *mem_info,
-                             VkDeviceSize offset, VkDeviceSize end_offset) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateMapImageLayouts(layer_data *device_data, VkDevice device, DEVICE_MEM_INFO const *mem_info,
+                                         VkDeviceSize offset, VkDeviceSize end_offset) {
     bool skip = false;
     // Iterate over all bound image ranges and verify that for any that overlap the map ranges, the layouts are
     // VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL
@@ -3453,10 +3697,9 @@
 
 // Helper function to validate correct usage bits set for buffers or images. Verify that (actual & desired) flags != 0 or, if strict
 // is true, verify that (actual & desired) flags == desired
-static bool ValidateUsageFlags(const layer_data *device_data, VkFlags actual, VkFlags desired, VkBool32 strict, uint64_t obj_handle,
-                               VulkanObjectType obj_type, std::string msgCode, char const *func_name, char const *usage_str) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
-
+bool CoreChecks::ValidateUsageFlags(const layer_data *device_data, VkFlags actual, VkFlags desired, VkBool32 strict,
+                                    uint64_t obj_handle, VulkanObjectType obj_type, const char *msgCode, char const *func_name,
+                                    char const *usage_str) {
     bool correct_usage = false;
     bool skip = false;
     const char *type_str = object_string[obj_type];
@@ -3468,16 +3711,14 @@
     if (!correct_usage) {
         if (msgCode == kVUIDUndefined) {
             // TODO: Fix callers with kVUIDUndefined to use correct validation checks.
-            skip =
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle,
-                        kVUID_Core_MemTrack_InvalidUsageFlag,
-                        "Invalid usage flag for %s 0x%" PRIx64 " used by %s. In this case, %s should have %s set during creation.",
-                        type_str, obj_handle, func_name, type_str, usage_str);
+            skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle,
+                           kVUID_Core_MemTrack_InvalidUsageFlag,
+                           "Invalid usage flag for %s %s used by %s. In this case, %s should have %s set during creation.",
+                           type_str, report_data->FormatHandle(obj_handle).c_str(), func_name, type_str, usage_str);
         } else {
-            skip =
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle, msgCode,
-                        "Invalid usage flag for %s 0x%" PRIx64 " used by %s. In this case, %s should have %s set during creation.",
-                        type_str, obj_handle, func_name, type_str, usage_str);
+            skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle, msgCode,
+                           "Invalid usage flag for %s %s used by %s. In this case, %s should have %s set during creation.",
+                           type_str, report_data->FormatHandle(obj_handle).c_str(), func_name, type_str, usage_str);
         }
     }
     return skip;
@@ -3485,42 +3726,40 @@
 
 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
 // where an error will be flagged if usage is not correct
-bool ValidateImageUsageFlags(layer_data *device_data, IMAGE_STATE const *image_state, VkFlags desired, bool strict,
-                             const std::string &msgCode, char const *func_name, char const *usage_string) {
+bool CoreChecks::ValidateImageUsageFlags(layer_data *device_data, IMAGE_STATE const *image_state, VkFlags desired, bool strict,
+                                         const char *msgCode, char const *func_name, char const *usage_string) {
     return ValidateUsageFlags(device_data, image_state->createInfo.usage, desired, strict, HandleToUint64(image_state->image),
                               kVulkanObjectTypeImage, msgCode, func_name, usage_string);
 }
 
-bool ValidateImageFormatFeatureFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
-                                     char const *func_name, const std::string &linear_vuid, const std::string &optimal_vuid) {
-    VkFormatProperties format_properties = GetFormatProperties(dev_data, image_state->createInfo.format);
-    const debug_report_data *report_data = core_validation::GetReportData(dev_data);
+bool CoreChecks::ValidateImageFormatFeatureFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
+                                                 char const *func_name, const char *linear_vuid, const char *optimal_vuid) {
+    VkFormatProperties format_properties = GetPDFormatProperties(image_state->createInfo.format);
     bool skip = false;
     if (image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR) {
         if ((format_properties.linearTilingFeatures & desired) != desired) {
-            skip |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                        HandleToUint64(image_state->image), linear_vuid,
-                        "In %s, invalid linearTilingFeatures (0x%08X) for format %u used by image %" PRIx64 ".", func_name,
-                        format_properties.linearTilingFeatures, image_state->createInfo.format, HandleToUint64(image_state->image));
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(image_state->image), linear_vuid,
+                            "In %s, invalid linearTilingFeatures (0x%08X) for format %u used by image %s.", func_name,
+                            format_properties.linearTilingFeatures, image_state->createInfo.format,
+                            report_data->FormatHandle(image_state->image).c_str());
         }
     } else if (image_state->createInfo.tiling == VK_IMAGE_TILING_OPTIMAL) {
         if ((format_properties.optimalTilingFeatures & desired) != desired) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(image_state->image), optimal_vuid,
-                            "In %s, invalid optimalTilingFeatures (0x%08X) for format %u used by image %" PRIx64 ".", func_name,
+                            "In %s, invalid optimalTilingFeatures (0x%08X) for format %u used by image %s.", func_name,
                             format_properties.optimalTilingFeatures, image_state->createInfo.format,
-                            HandleToUint64(image_state->image));
+                            report_data->FormatHandle(image_state->image).c_str());
         }
     }
     return skip;
 }
 
-bool ValidateImageSubresourceLayers(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
-                                    const VkImageSubresourceLayers *subresource_layers, char const *func_name, char const *member,
-                                    uint32_t i) {
+bool CoreChecks::ValidateImageSubresourceLayers(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
+                                                const VkImageSubresourceLayers *subresource_layers, char const *func_name,
+                                                char const *member, uint32_t i) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(dev_data);
     // layerCount must not be zero
     if (subresource_layers->layerCount == 0) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -3547,16 +3786,15 @@
 
 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
 // where an error will be flagged if usage is not correct
-bool ValidateBufferUsageFlags(const layer_data *device_data, BUFFER_STATE const *buffer_state, VkFlags desired, bool strict,
-                              const std::string &msgCode, char const *func_name, char const *usage_string) {
+bool CoreChecks::ValidateBufferUsageFlags(const layer_data *device_data, BUFFER_STATE const *buffer_state, VkFlags desired,
+                                          bool strict, const char *msgCode, char const *func_name, char const *usage_string) {
     return ValidateUsageFlags(device_data, buffer_state->createInfo.usage, desired, strict, HandleToUint64(buffer_state->buffer),
                               kVulkanObjectTypeBuffer, msgCode, func_name, usage_string);
 }
 
-bool ValidateBufferViewRange(const layer_data *device_data, const BUFFER_STATE *buffer_state,
-                             const VkBufferViewCreateInfo *pCreateInfo, const VkPhysicalDeviceLimits *device_limits) {
+bool CoreChecks::ValidateBufferViewRange(const layer_data *device_data, const BUFFER_STATE *buffer_state,
+                                         const VkBufferViewCreateInfo *pCreateInfo, const VkPhysicalDeviceLimits *device_limits) {
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
     const VkDeviceSize &range = pCreateInfo->range;
     if (range != VK_WHOLE_SIZE) {
@@ -3569,7 +3807,7 @@
                             range);
         }
         // Range must be a multiple of the element size of format
-        const size_t format_size = FormatSize(pCreateInfo->format);
+        const size_t format_size = FormatElementSize(pCreateInfo->format);
         if (range % format_size != 0) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00929",
@@ -3601,11 +3839,10 @@
     return skip;
 }
 
-bool ValidateBufferViewBuffer(const layer_data *device_data, const BUFFER_STATE *buffer_state,
-                              const VkBufferViewCreateInfo *pCreateInfo) {
+bool CoreChecks::ValidateBufferViewBuffer(const layer_data *device_data, const BUFFER_STATE *buffer_state,
+                                          const VkBufferViewCreateInfo *pCreateInfo) {
     bool skip = false;
-    const debug_report_data *report_data = GetReportData(device_data);
-    const VkFormatProperties format_properties = GetFormatProperties(device_data, pCreateInfo->format);
+    const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->format);
     if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) &&
         !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
@@ -3623,47 +3860,86 @@
     return skip;
 }
 
-bool PreCallValidateCreateBuffer(layer_data *device_data, const VkBufferCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
+                                             const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
 
     // TODO: Add check for "VUID-vkCreateBuffer-flags-00911"        (sparse address space accounting)
 
-    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && (!GetEnabledFeatures(device_data)->core.sparseBinding)) {
+    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && (!GetEnabledFeatures()->core.sparseBinding)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkBufferCreateInfo-flags-00915",
                         "vkCreateBuffer(): the sparseBinding device feature is disabled: Buffers cannot be created with the "
                         "VK_BUFFER_CREATE_SPARSE_BINDING_BIT set.");
     }
 
-    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) &&
-        (!GetEnabledFeatures(device_data)->core.sparseResidencyBuffer)) {
+    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && (!GetEnabledFeatures()->core.sparseResidencyBuffer)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkBufferCreateInfo-flags-00916",
                         "vkCreateBuffer(): the sparseResidencyBuffer device feature is disabled: Buffers cannot be created with "
                         "the VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT set.");
     }
 
-    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) &&
-        (!GetEnabledFeatures(device_data)->core.sparseResidencyAliased)) {
+    if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && (!GetEnabledFeatures()->core.sparseResidencyAliased)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkBufferCreateInfo-flags-00917",
                         "vkCreateBuffer(): the sparseResidencyAliased device feature is disabled: Buffers cannot be created with "
                         "the VK_BUFFER_CREATE_SPARSE_ALIASED_BIT set.");
     }
+
+    auto chained_devaddr_struct = lvl_find_in_chain<VkBufferDeviceAddressCreateInfoEXT>(pCreateInfo->pNext);
+    if (chained_devaddr_struct) {
+        if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
+            chained_devaddr_struct->deviceAddress != 0) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkBufferCreateInfo-deviceAddress-02604",
+                            "vkCreateBuffer(): Non-zero VkBufferDeviceAddressCreateInfoEXT::deviceAddress "
+                            "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT.");
+        }
+    }
+
+    if ((pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
+        !GetEnabledFeatures()->buffer_address.bufferDeviceAddressCaptureReplay) {
+        skip |= log_msg(
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            "VUID-VkBufferCreateInfo-flags-02605",
+            "vkCreateBuffer(): the bufferDeviceAddressCaptureReplay device feature is disabled: Buffers cannot be created with "
+            "the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT set.");
+    }
+
+    if ((pCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) &&
+        !GetEnabledFeatures()->buffer_address.bufferDeviceAddress) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkBufferCreateInfo-usage-02606",
+                        "vkCreateBuffer(): the bufferDeviceAddress device feature is disabled: Buffers cannot be created with "
+                        "the VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT set.");
+    }
+
+    if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
+        skip |=
+            ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
+                                  "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", "VUID-VkBufferCreateInfo-sharingMode-01419",
+                                  "VUID-VkBufferCreateInfo-sharingMode-01419", false);
+    }
+
     return skip;
 }
 
-void PostCallRecordCreateBuffer(layer_data *device_data, const VkBufferCreateInfo *pCreateInfo, VkBuffer *pBuffer) {
+void CoreChecks::PostCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer, VkResult result) {
+    if (result != VK_SUCCESS) return;
     // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
-    GetBufferMap(device_data)
-        ->insert(std::make_pair(*pBuffer, std::unique_ptr<BUFFER_STATE>(new BUFFER_STATE(*pBuffer, pCreateInfo))));
+    GetBufferMap()->insert(std::make_pair(*pBuffer, std::unique_ptr<BUFFER_STATE>(new BUFFER_STATE(*pBuffer, pCreateInfo))));
 }
 
-bool PreCallValidateCreateBufferView(const layer_data *device_data, const VkBufferViewCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
+                                                 const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     bool skip = false;
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
-    BUFFER_STATE *buffer_state = GetBufferState(device_data, pCreateInfo->buffer);
+    BUFFER_STATE *buffer_state = GetBufferState(pCreateInfo->buffer);
     // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
     if (buffer_state) {
         skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCreateBufferView()",
@@ -3684,7 +3960,7 @@
                             pCreateInfo->offset, buffer_state->createInfo.size);
         }
 
-        const VkPhysicalDeviceLimits *device_limits = &(GetPhysicalDeviceProperties(device_data)->limits);
+        const VkPhysicalDeviceLimits *device_limits = &(GetPDProperties()->limits);
         // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment
         if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
@@ -3701,14 +3977,15 @@
     return skip;
 }
 
-void PostCallRecordCreateBufferView(layer_data *device_data, const VkBufferViewCreateInfo *pCreateInfo, VkBufferView *pView) {
-    (*GetBufferViewMap(device_data))[*pView] = std::unique_ptr<BUFFER_VIEW_STATE>(new BUFFER_VIEW_STATE(*pView, pCreateInfo));
+void CoreChecks::PostCallRecordCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView, VkResult result) {
+    if (result != VK_SUCCESS) return;
+    (*GetBufferViewMap())[*pView] = std::unique_ptr<BUFFER_VIEW_STATE>(new BUFFER_VIEW_STATE(*pView, pCreateInfo));
 }
 
 // For the given format verify that the aspect masks make sense
-bool ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask,
-                             const char *func_name, const char *vuid) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format,
+                                         VkImageAspectFlags aspect_mask, const char *func_name, const char *vuid) {
     bool skip = false;
     VkDebugReportObjectTypeEXT objectType = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
     if (image != VK_NULL_HANDLE) {
@@ -3766,15 +4043,10 @@
     return skip;
 }
 
-struct SubresourceRangeErrorCodes {
-    std::string base_mip_err, mip_count_err, base_layer_err, layer_count_err;
-};
-
-bool ValidateImageSubresourceRange(const layer_data *device_data, const uint32_t image_mip_count, const uint32_t image_layer_count,
-                                   const VkImageSubresourceRange &subresourceRange, const char *cmd_name, const char *param_name,
-                                   const char *image_layer_count_var_name, const uint64_t image_handle,
-                                   SubresourceRangeErrorCodes errorCodes) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateImageSubresourceRange(const layer_data *device_data, const uint32_t image_mip_count,
+                                               const uint32_t image_layer_count, const VkImageSubresourceRange &subresourceRange,
+                                               const char *cmd_name, const char *param_name, const char *image_layer_count_var_name,
+                                               const uint64_t image_handle, SubresourceRangeErrorCodes errorCodes) {
     bool skip = false;
 
     // Validate mip levels
@@ -3835,9 +4107,10 @@
     return skip;
 }
 
-bool ValidateCreateImageViewSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                             bool is_imageview_2d_type, const VkImageSubresourceRange &subresourceRange) {
-    bool is_khr_maintenance1 = GetDeviceExtensions(device_data)->vk_khr_maintenance1;
+bool CoreChecks::ValidateCreateImageViewSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
+                                                         bool is_imageview_2d_type,
+                                                         const VkImageSubresourceRange &subresourceRange) {
+    bool is_khr_maintenance1 = GetDeviceExtensions()->vk_khr_maintenance1;
     bool is_image_slicable = image_state->createInfo.imageType == VK_IMAGE_TYPE_3D &&
                              (image_state->createInfo.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR);
     bool is_3D_to_2D_map = is_khr_maintenance1 && is_image_slicable && is_imageview_2d_type;
@@ -3861,8 +4134,8 @@
                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
 }
 
-bool ValidateCmdClearColorSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                           const VkImageSubresourceRange &subresourceRange, const char *param_name) {
+bool CoreChecks::ValidateCmdClearColorSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
+                                                       const VkImageSubresourceRange &subresourceRange, const char *param_name) {
     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
     subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearColorImage-baseMipLevel-01470";
     subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearColorImage-pRanges-01692";
@@ -3874,8 +4147,8 @@
                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
 }
 
-bool ValidateCmdClearDepthSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                           const VkImageSubresourceRange &subresourceRange, const char *param_name) {
+bool CoreChecks::ValidateCmdClearDepthSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
+                                                       const VkImageSubresourceRange &subresourceRange, const char *param_name) {
     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
     subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474";
     subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01694";
@@ -3887,9 +4160,9 @@
                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
 }
 
-bool ValidateImageBarrierSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                          const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
-                                          const char *param_name) {
+bool CoreChecks::ValidateImageBarrierSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
+                                                      const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
+                                                      const char *param_name) {
     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
     subresourceRangeErrorCodes.base_mip_err = "VUID-VkImageMemoryBarrier-subresourceRange-01486";
     subresourceRangeErrorCodes.mip_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01724";
@@ -3901,10 +4174,11 @@
                                          subresourceRangeErrorCodes);
 }
 
-bool PreCallValidateCreateImageView(layer_data *device_data, const VkImageViewCreateInfo *create_info) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    IMAGE_STATE *image_state = GetImageState(device_data, create_info->image);
+    IMAGE_STATE *image_state = GetImageState(pCreateInfo->image);
     if (image_state) {
         skip |= ValidateImageUsageFlags(
             device_data, image_state,
@@ -3919,20 +4193,20 @@
         // Checks imported from image layer
         skip |= ValidateCreateImageViewSubresourceRange(
             device_data, image_state,
-            create_info->viewType == VK_IMAGE_VIEW_TYPE_2D || create_info->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
-            create_info->subresourceRange);
+            pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D || pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+            pCreateInfo->subresourceRange);
 
         VkImageCreateFlags image_flags = image_state->createInfo.flags;
         VkFormat image_format = image_state->createInfo.format;
         VkImageUsageFlags image_usage = image_state->createInfo.usage;
         VkImageTiling image_tiling = image_state->createInfo.tiling;
-        VkFormat view_format = create_info->format;
-        VkImageAspectFlags aspect_mask = create_info->subresourceRange.aspectMask;
+        VkFormat view_format = pCreateInfo->format;
+        VkImageAspectFlags aspect_mask = pCreateInfo->subresourceRange.aspectMask;
         VkImageType image_type = image_state->createInfo.imageType;
-        VkImageViewType view_type = create_info->viewType;
+        VkImageViewType view_type = pCreateInfo->viewType;
 
         // If there's a chained VkImageViewUsageCreateInfo struct, modify image_usage to match
-        auto chained_ivuci_struct = lvl_find_in_chain<VkImageViewUsageCreateInfoKHR>(create_info->pNext);
+        auto chained_ivuci_struct = lvl_find_in_chain<VkImageViewUsageCreateInfoKHR>(pCreateInfo->pNext);
         if (chained_ivuci_struct) {
             if (chained_ivuci_struct->usage & ~image_usage) {
                 std::stringstream ss;
@@ -3940,7 +4214,7 @@
                    << chained_ivuci_struct->usage << ") must not include flags not present in underlying image's usage (0x"
                    << image_usage << ").";
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewUsageCreateInfo-usage-01587", "%s",
+                                HandleToUint64(pCreateInfo->image), "VUID-VkImageViewUsageCreateInfo-usage-01587", "%s",
                                 ss.str().c_str());
             }
 
@@ -3973,22 +4247,22 @@
                        << " is not compatible with plane " << plane << " of underlying image format "
                        << string_VkFormat(image_format) << ", must be " << string_VkFormat(compat_format) << ".";
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                    HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-01586", "%s",
+                                    HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01586", "%s",
                                     ss.str().c_str());
                 }
             } else {
-                if ((!GetDeviceExtensions(device_data)->vk_khr_maintenance2 ||
+                if ((!GetDeviceExtensions()->vk_khr_maintenance2 ||
                      !(image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR))) {
                     // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
                     if (FormatCompatibilityClass(image_format) != FormatCompatibilityClass(view_format)) {
                         std::stringstream ss;
                         ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
-                           << " is not in the same format compatibility class as image (" << HandleToUint64(create_info->image)
-                           << ")  format " << string_VkFormat(image_format)
+                           << " is not in the same format compatibility class as image ("
+                           << report_data->FormatHandle(pCreateInfo->image).c_str() << ")  format " << string_VkFormat(image_format)
                            << ".  Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
                            << "can support ImageViews with differing formats but they must be in the same compatibility class.";
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                        HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-01018", "%s",
+                                        HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01018", "%s",
                                         ss.str().c_str());
                     }
                 }
@@ -3998,11 +4272,11 @@
             if (image_format != view_format) {
                 std::stringstream ss;
                 ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from image "
-                   << HandleToUint64(create_info->image) << " format " << string_VkFormat(image_format)
+                   << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
                    << ".  Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
                 skip |=
                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-01019", "%s", ss.str().c_str());
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01019", "%s", ss.str().c_str());
             }
         }
 
@@ -4013,7 +4287,7 @@
             case VK_IMAGE_TYPE_1D:
                 if (view_type != VK_IMAGE_VIEW_TYPE_1D && view_type != VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                    HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
+                                    HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
                                     "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                     string_VkImageViewType(view_type), string_VkImageType(image_type));
                 }
@@ -4023,32 +4297,32 @@
                     if ((view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) &&
                         !(image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                        HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-01003",
+                                        HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01003",
                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
                     } else if (view_type != VK_IMAGE_VIEW_TYPE_CUBE && view_type != VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                        HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
+                                        HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
                     }
                 }
                 break;
             case VK_IMAGE_TYPE_3D:
-                if (GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+                if (GetDeviceExtensions()->vk_khr_maintenance1) {
                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
                         if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
                             if (!(image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) {
                                 skip |=
                                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-01005",
+                                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01005",
                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                             string_VkImageViewType(view_type), string_VkImageType(image_type));
                             } else if ((image_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
                                                        VK_IMAGE_CREATE_SPARSE_ALIASED_BIT))) {
                                 skip |=
                                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
+                                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
                                             "when the VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or "
                                             "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags are enabled.",
@@ -4056,7 +4330,7 @@
                             }
                         } else {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                            HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
+                                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                             string_VkImageViewType(view_type), string_VkImageType(image_type));
                         }
@@ -4064,7 +4338,7 @@
                 } else {
                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                        HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
+                                        HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
                     }
@@ -4074,62 +4348,60 @@
                 break;
         }
 
-        VkFormatProperties format_properties = GetFormatProperties(device_data, view_format);
-        bool check_tiling_features = false;
-        VkFormatFeatureFlags tiling_features = 0;
-        if (image_tiling == VK_IMAGE_TILING_LINEAR) {
-            tiling_features = format_properties.linearTilingFeatures;
-            check_tiling_features = true;
-        } else if (image_tiling == VK_IMAGE_TILING_OPTIMAL) {
-            tiling_features = format_properties.optimalTilingFeatures;
-            check_tiling_features = true;
+        // External format checks needed when VK_ANDROID_external_memory_android_hardware_buffer enabled
+        if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+            skip |= ValidateCreateImageViewANDROID(device_data, pCreateInfo);
         }
 
-        if (check_tiling_features) {
-            if (tiling_features == 0) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-None-02273",
-                                "vkCreateImageView() pCreateInfo->format %s cannot be used with an image having the %s flag set.",
-                                string_VkFormat(view_format), string_VkImageTiling(image_tiling));
-            } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-usage-02274",
-                                "vkCreateImageView() pCreateInfo->format %s cannot be used with an image having the %s and "
-                                "VK_IMAGE_USAGE_SAMPLED_BIT flags set.",
-                                string_VkFormat(view_format), string_VkImageTiling(image_tiling));
-            } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-usage-02275",
-                                "vkCreateImageView() pCreateInfo->format %s cannot be used with an image having the %s and "
-                                "VK_IMAGE_USAGE_STORAGE_BIT flags set.",
-                                string_VkFormat(view_format), string_VkImageTiling(image_tiling));
-            } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
-                       !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-usage-02276",
-                                "vkCreateImageView() pCreateInfo->format %s cannot be used with an image having the %s and "
-                                "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT flags set.",
-                                string_VkFormat(view_format), string_VkImageTiling(image_tiling));
-            } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
-                       !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-usage-02277",
-                                "vkCreateImageView() pCreateInfo->format %s cannot be used with an image having the %s and "
-                                "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT flags set.",
-                                string_VkFormat(view_format), string_VkImageTiling(image_tiling));
-            }
+        VkFormatProperties format_properties = GetPDFormatProperties(view_format);
+        VkFormatFeatureFlags tiling_features = (image_tiling & VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
+                                                                                       : format_properties.optimalTilingFeatures;
+
+        if (tiling_features == 0) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-None-02273",
+                            "vkCreateImageView(): pCreateInfo->format %s with tiling %s has no supported format features on this "
+                            "physical device.",
+                            string_VkFormat(view_format), string_VkImageTiling(image_tiling));
+        } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02274",
+                            "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
+                            "VK_IMAGE_USAGE_SAMPLED_BIT.",
+                            string_VkFormat(view_format), string_VkImageTiling(image_tiling));
+        } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02275",
+                            "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
+                            "VK_IMAGE_USAGE_STORAGE_BIT.",
+                            string_VkFormat(view_format), string_VkImageTiling(image_tiling));
+        } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
+                   !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02276",
+                            "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
+                            "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
+                            string_VkFormat(view_format), string_VkImageTiling(image_tiling));
+        } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
+                   !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                            HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02277",
+                            "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
+                            "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
+                            string_VkFormat(view_format), string_VkImageTiling(image_tiling));
         }
+
         if (image_usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) {
             if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02086",
+                                HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02086",
                                 "vkCreateImageView() If image was created with usage containing "
                                 "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, viewType must be "
                                 "VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
             }
             if (view_format != VK_FORMAT_R8_UINT) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                                HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02087",
+                                HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02087",
                                 "vkCreateImageView() If image was created with usage containing "
                                 "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT.");
             }
@@ -4138,18 +4410,25 @@
     return skip;
 }
 
-void PostCallRecordCreateImageView(layer_data *device_data, const VkImageViewCreateInfo *create_info, VkImageView view) {
-    auto image_view_map = GetImageViewMap(device_data);
-    (*image_view_map)[view] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(view, create_info));
+void CoreChecks::PostCallRecordCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView, VkResult result) {
+    if (result != VK_SUCCESS) return;
+    auto image_view_map = GetImageViewMap();
+    (*image_view_map)[*pView] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(*pView, pCreateInfo));
 
-    auto image_state = GetImageState(device_data, create_info->image);
-    auto &sub_res_range = (*image_view_map)[view].get()->create_info.subresourceRange;
+    auto image_state = GetImageState(pCreateInfo->image);
+    auto &sub_res_range = (*image_view_map)[*pView].get()->create_info.subresourceRange;
     sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
     sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
 }
 
-bool PreCallValidateCmdCopyBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buffer_state,
-                                  BUFFER_STATE *dst_buffer_state) {
+bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
+                                              uint32_t regionCount, const VkBufferCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_buffer_state = GetBufferState(srcBuffer);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+
     bool skip = false;
     skip |=
         ValidateMemoryIsBoundToBuffer(device_data, src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-srcBuffer-00119");
@@ -4170,96 +4449,117 @@
     return skip;
 }
 
-void PreCallRecordCmdCopyBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buffer_state,
-                                BUFFER_STATE *dst_buffer_state) {
+void CoreChecks::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
+                                            uint32_t regionCount, const VkBufferCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_buffer_state = GetBufferState(srcBuffer);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+
     // Update bindings between buffers and cmd buffer
     AddCommandBufferBindingBuffer(device_data, cb_node, src_buffer_state);
     AddCommandBufferBindingBuffer(device_data, cb_node, dst_buffer_state);
 }
 
-static bool ValidateIdleBuffer(layer_data *device_data, VkBuffer buffer) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::ValidateIdleBuffer(layer_data *device_data, VkBuffer buffer) {
     bool skip = false;
-    auto buffer_state = GetBufferState(device_data, buffer);
+    auto buffer_state = GetBufferState(buffer);
     if (!buffer_state) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, HandleToUint64(buffer),
-                        kVUID_Core_DrawState_DoubleDestroy, "Cannot free buffer 0x%" PRIx64 " that has not been allocated.",
-                        HandleToUint64(buffer));
+                        kVUID_Core_DrawState_DoubleDestroy, "Cannot free buffer %s that has not been allocated.",
+                        report_data->FormatHandle(buffer).c_str());
     } else {
         if (buffer_state->in_use.load()) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                             HandleToUint64(buffer), "VUID-vkDestroyBuffer-buffer-00922",
-                            "Cannot free buffer 0x%" PRIx64 " that is in use by a command buffer.", HandleToUint64(buffer));
+                            "Cannot free buffer %s that is in use by a command buffer.", report_data->FormatHandle(buffer).c_str());
         }
     }
     return skip;
 }
 
-bool PreCallValidateDestroyImageView(layer_data *device_data, VkImageView image_view, IMAGE_VIEW_STATE **image_view_state,
-                                     VK_OBJECT *obj_struct) {
-    *image_view_state = GetImageViewState(device_data, image_view);
-    *obj_struct = {HandleToUint64(image_view), kVulkanObjectTypeImageView};
-    if (GetDisables(device_data)->destroy_image_view) return false;
+bool CoreChecks::PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
+    VK_OBJECT obj_struct = {HandleToUint64(imageView), kVulkanObjectTypeImageView};
+
     bool skip = false;
-    if (*image_view_state) {
-        skip |= ValidateObjectNotInUse(device_data, *image_view_state, *obj_struct, "vkDestroyImageView",
+    if (image_view_state) {
+        skip |= ValidateObjectNotInUse(device_data, image_view_state, obj_struct, "vkDestroyImageView",
                                        "VUID-vkDestroyImageView-imageView-01026");
     }
     return skip;
 }
 
-void PreCallRecordDestroyImageView(layer_data *device_data, VkImageView image_view, IMAGE_VIEW_STATE *image_view_state,
-                                   VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
+    if (!image_view_state) return;
+    VK_OBJECT obj_struct = {HandleToUint64(imageView), kVulkanObjectTypeImageView};
+
     // Any bound cmd buffers are now invalid
     InvalidateCommandBuffers(device_data, image_view_state->cb_bindings, obj_struct);
-    (*GetImageViewMap(device_data)).erase(image_view);
+    (*GetImageViewMap()).erase(imageView);
 }
 
-bool PreCallValidateDestroyBuffer(layer_data *device_data, VkBuffer buffer, BUFFER_STATE **buffer_state, VK_OBJECT *obj_struct) {
-    *buffer_state = GetBufferState(device_data, buffer);
-    *obj_struct = {HandleToUint64(buffer), kVulkanObjectTypeBuffer};
-    if (GetDisables(device_data)->destroy_buffer) return false;
+bool CoreChecks::PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto buffer_state = GetBufferState(buffer);
+
     bool skip = false;
-    if (*buffer_state) {
+    if (buffer_state) {
         skip |= ValidateIdleBuffer(device_data, buffer);
     }
     return skip;
 }
 
-void PreCallRecordDestroyBuffer(layer_data *device_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!buffer) return;
+    auto buffer_state = GetBufferState(buffer);
+    VK_OBJECT obj_struct = {HandleToUint64(buffer), kVulkanObjectTypeBuffer};
+
     InvalidateCommandBuffers(device_data, buffer_state->cb_bindings, obj_struct);
     for (auto mem_binding : buffer_state->GetBoundMemory()) {
-        auto mem_info = GetMemObjInfo(device_data, mem_binding);
+        auto mem_info = GetMemObjInfo(mem_binding);
         if (mem_info) {
-            core_validation::RemoveBufferMemoryRange(HandleToUint64(buffer), mem_info);
+            RemoveBufferMemoryRange(HandleToUint64(buffer), mem_info);
         }
     }
-    ClearMemoryObjectBindings(device_data, HandleToUint64(buffer), kVulkanObjectTypeBuffer);
+    ClearMemoryObjectBindings(HandleToUint64(buffer), kVulkanObjectTypeBuffer);
     EraseQFOReleaseBarriers<VkBufferMemoryBarrier>(device_data, buffer);
-    GetBufferMap(device_data)->erase(buffer_state->buffer);
+    GetBufferMap()->erase(buffer_state->buffer);
 }
 
-bool PreCallValidateDestroyBufferView(layer_data *device_data, VkBufferView buffer_view, BUFFER_VIEW_STATE **buffer_view_state,
-                                      VK_OBJECT *obj_struct) {
-    *buffer_view_state = GetBufferViewState(device_data, buffer_view);
-    *obj_struct = {HandleToUint64(buffer_view), kVulkanObjectTypeBufferView};
-    if (GetDisables(device_data)->destroy_buffer_view) return false;
+bool CoreChecks::PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView,
+                                                  const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto buffer_view_state = GetBufferViewState(bufferView);
+    VK_OBJECT obj_struct = {HandleToUint64(bufferView), kVulkanObjectTypeBufferView};
     bool skip = false;
-    if (*buffer_view_state) {
-        skip |= ValidateObjectNotInUse(device_data, *buffer_view_state, *obj_struct, "vkDestroyBufferView",
+    if (buffer_view_state) {
+        skip |= ValidateObjectNotInUse(device_data, buffer_view_state, obj_struct, "vkDestroyBufferView",
                                        "VUID-vkDestroyBufferView-bufferView-00936");
     }
     return skip;
 }
 
-void PreCallRecordDestroyBufferView(layer_data *device_data, VkBufferView buffer_view, BUFFER_VIEW_STATE *buffer_view_state,
-                                    VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!bufferView) return;
+    auto buffer_view_state = GetBufferViewState(bufferView);
+    VK_OBJECT obj_struct = {HandleToUint64(bufferView), kVulkanObjectTypeBufferView};
+
     // Any bound cmd buffers are now invalid
     InvalidateCommandBuffers(device_data, buffer_view_state->cb_bindings, obj_struct);
-    GetBufferViewMap(device_data)->erase(buffer_view);
+    GetBufferViewMap()->erase(bufferView);
 }
 
-bool PreCallValidateCmdFillBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
+bool CoreChecks::PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                              VkDeviceSize size, uint32_t data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto buffer_state = GetBufferState(dstBuffer);
     bool skip = false;
     skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-dstBuffer-00031");
     skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdFillBuffer()",
@@ -4274,13 +4574,17 @@
     return skip;
 }
 
-void PreCallRecordCmdFillBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
+void CoreChecks::PreCallRecordCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                            VkDeviceSize size, uint32_t data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto buffer_state = GetBufferState(dstBuffer);
     // Update bindings between buffer and cmd buffer
     AddCommandBufferBindingBuffer(device_data, cb_node, buffer_state);
 }
 
-bool ValidateBufferImageCopyData(const debug_report_data *report_data, uint32_t regionCount, const VkBufferImageCopy *pRegions,
-                                 IMAGE_STATE *image_state, const char *function) {
+bool CoreChecks::ValidateBufferImageCopyData(const debug_report_data *report_data, uint32_t regionCount,
+                                             const VkBufferImageCopy *pRegions, IMAGE_STATE *image_state, const char *function) {
     bool skip = false;
 
     for (uint32_t i = 0; i < regionCount; i++) {
@@ -4315,14 +4619,14 @@
         }
 
         // If the the calling command's VkImage parameter's format is not a depth/stencil format,
-        // then bufferOffset must be a multiple of the calling command's VkImage parameter's texel size
-        auto texel_size = FormatSize(image_state->createInfo.format);
-        if (!FormatIsDepthAndStencil(image_state->createInfo.format) && SafeModulo(pRegions[i].bufferOffset, texel_size) != 0) {
+        // then bufferOffset must be a multiple of the calling command's VkImage parameter's element size
+        uint32_t element_size = FormatElementSize(image_state->createInfo.format);
+        if (!FormatIsDepthAndStencil(image_state->createInfo.format) && SafeModulo(pRegions[i].bufferOffset, element_size) != 0) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00193",
                             "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64
-                            " must be a multiple of this format's texel size (" PRINTF_SIZE_T_SPECIFIER ").",
-                            function, i, pRegions[i].bufferOffset, texel_size);
+                            " must be a multiple of this format's texel size (%" PRIu32 ").",
+                            function, i, pRegions[i].bufferOffset, element_size);
         }
 
         //  BufferOffset must be a multiple of 4
@@ -4371,7 +4675,7 @@
 
         // Checks that apply only to compressed images
         if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
-            auto block_size = FormatCompressedTexelBlockExtent(image_state->createInfo.format);
+            auto block_size = FormatTexelBlockExtent(image_state->createInfo.format);
 
             //  BufferRowLength must be a multiple of block width
             if (SafeModulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
@@ -4404,12 +4708,12 @@
             }
 
             // bufferOffset must be a multiple of block size (linear bytes)
-            size_t block_size_in_bytes = FormatSize(image_state->createInfo.format);
+            uint32_t block_size_in_bytes = FormatElementSize(image_state->createInfo.format);
             if (SafeModulo(pRegions[i].bufferOffset, block_size_in_bytes) != 0) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00206",
                                 "%s(): pRegion[%d] bufferOffset (0x%" PRIxLEAST64
-                                ") must be a multiple of the compressed image's texel block size (" PRINTF_SIZE_T_SPECIFIER ")..",
+                                ") must be a multiple of the compressed image's texel block size (%" PRIu32 ")..",
                                 function, i, pRegions[i].bufferOffset, block_size_in_bytes);
             }
 
@@ -4453,7 +4757,7 @@
 }
 
 static bool ValidateImageBounds(const debug_report_data *report_data, const IMAGE_STATE *image_state, const uint32_t regionCount,
-                                const VkBufferImageCopy *pRegions, const char *func_name, std::string msg_code) {
+                                const VkBufferImageCopy *pRegions, const char *func_name, const char *msg_code) {
     bool skip = false;
     const VkImageCreateInfo *image_info = &(image_state->createInfo);
 
@@ -4473,7 +4777,7 @@
 
         // If we're using a compressed format, valid extent is rounded up to multiple of block size (per 18.1)
         if (FormatIsCompressed(image_info->format)) {
-            auto block_extent = FormatCompressedTexelBlockExtent(image_info->format);
+            auto block_extent = FormatTexelBlockExtent(image_info->format);
             if (image_extent.width % block_extent.width) {
                 image_extent.width += (block_extent.width - (image_extent.width % block_extent.width));
             }
@@ -4496,7 +4800,7 @@
 
 static inline bool ValidateBufferBounds(const debug_report_data *report_data, IMAGE_STATE *image_state, BUFFER_STATE *buff_state,
                                         uint32_t regionCount, const VkBufferImageCopy *pRegions, const char *func_name,
-                                        std::string msg_code) {
+                                        const char *msg_code) {
     bool skip = false;
 
     VkDeviceSize buffer_size = buff_state->createInfo.size;
@@ -4506,18 +4810,18 @@
 
         VkDeviceSize buffer_width = (0 == pRegions[i].bufferRowLength ? copy_extent.width : pRegions[i].bufferRowLength);
         VkDeviceSize buffer_height = (0 == pRegions[i].bufferImageHeight ? copy_extent.height : pRegions[i].bufferImageHeight);
-        VkDeviceSize unit_size = FormatSize(image_state->createInfo.format);  // size (bytes) of texel or block
+        VkDeviceSize unit_size = FormatElementSize(image_state->createInfo.format);  // size (bytes) of texel or block
 
         // Handle special buffer packing rules for specific depth/stencil formats
         if (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
-            unit_size = FormatSize(VK_FORMAT_S8_UINT);
+            unit_size = FormatElementSize(VK_FORMAT_S8_UINT);
         } else if (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
             switch (image_state->createInfo.format) {
                 case VK_FORMAT_D16_UNORM_S8_UINT:
-                    unit_size = FormatSize(VK_FORMAT_D16_UNORM);
+                    unit_size = FormatElementSize(VK_FORMAT_D16_UNORM);
                     break;
                 case VK_FORMAT_D32_SFLOAT_S8_UINT:
-                    unit_size = FormatSize(VK_FORMAT_D32_SFLOAT);
+                    unit_size = FormatElementSize(VK_FORMAT_D32_SFLOAT);
                     break;
                 case VK_FORMAT_X8_D24_UNORM_PACK32:  // Fall through
                 case VK_FORMAT_D24_UNORM_S8_UINT:
@@ -4530,7 +4834,7 @@
 
         if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
             // Switch to texel block units, rounding up for any partially-used blocks
-            auto block_dim = FormatCompressedTexelBlockExtent(image_state->createInfo.format);
+            auto block_dim = FormatTexelBlockExtent(image_state->createInfo.format);
             buffer_width = (buffer_width + block_dim.width - 1) / block_dim.width;
             buffer_height = (buffer_height + block_dim.height - 1) / block_dim.height;
 
@@ -4561,19 +4865,23 @@
     return skip;
 }
 
-bool PreCallValidateCmdCopyImageToBuffer(layer_data *device_data, VkImageLayout srcImageLayout, GLOBAL_CB_NODE *cb_node,
-                                         IMAGE_STATE *src_image_state, BUFFER_STATE *dst_buffer_state, uint32_t regionCount,
-                                         const VkBufferImageCopy *pRegions, const char *func_name) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                                     VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+
     bool skip = ValidateBufferImageCopyData(report_data, regionCount, pRegions, src_image_state, "vkCmdCopyImageToBuffer");
 
     // Validate command buffer state
     skip |= ValidateCmd(device_data, cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
 
     // Command pool must support graphics, compute, or transfer operations
-    auto pPool = GetCommandPoolNode(device_data, cb_node->createInfo.commandPool);
+    auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
 
-    VkQueueFlags queue_flags = GetPhysDevProperties(device_data)->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
+    VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
+
     if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyImageToBuffer-commandBuffer-cmdpool",
@@ -4599,15 +4907,15 @@
     skip |= ValidateBufferUsageFlags(device_data, dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
                                      "VUID-vkCmdCopyImageToBuffer-dstBuffer-00191", "vkCmdCopyImageToBuffer()",
                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
-    if (GetApiVersion(device_data) >= VK_API_VERSION_1_1 || GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+    if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
         skip |= ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT,
                                                 "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-srcImage-01998",
                                                 "VUID-vkCmdCopyImageToBuffer-srcImage-01998");
     }
     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-renderpass");
     bool hit_error = false;
-    const std::string src_invalid_layout_vuid =
-        (src_image_state->shared_presentable && core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+    const char *src_invalid_layout_vuid =
+        (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
             ? "VUID-vkCmdCopyImageToBuffer-srcImageLayout-01397"
             : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190";
     for (uint32_t i = 0; i < regionCount; ++i) {
@@ -4629,30 +4937,38 @@
     return skip;
 }
 
-void PreCallRecordCmdCopyImageToBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                       BUFFER_STATE *dst_buffer_state, uint32_t region_count, const VkBufferImageCopy *regions,
-                                       VkImageLayout src_image_layout) {
+void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                                   VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_image_state = GetImageState(srcImage);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+
     // Make sure that all image slices are updated to correct layout
-    for (uint32_t i = 0; i < region_count; ++i) {
-        SetImageLayout(device_data, cb_node, src_image_state, regions[i].imageSubresource, src_image_layout);
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout);
     }
     // Update bindings between buffer/image and cmd buffer
     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
     AddCommandBufferBindingBuffer(device_data, cb_node, dst_buffer_state);
 }
 
-bool PreCallValidateCmdCopyBufferToImage(layer_data *device_data, VkImageLayout dstImageLayout, GLOBAL_CB_NODE *cb_node,
-                                         BUFFER_STATE *src_buffer_state, IMAGE_STATE *dst_image_state, uint32_t regionCount,
-                                         const VkBufferImageCopy *pRegions, const char *func_name) {
-    const debug_report_data *report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
+                                                     VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                     const VkBufferImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_buffer_state = GetBufferState(srcBuffer);
+    auto dst_image_state = GetImageState(dstImage);
+
     bool skip = ValidateBufferImageCopyData(report_data, regionCount, pRegions, dst_image_state, "vkCmdCopyBufferToImage");
 
     // Validate command buffer state
     skip |= ValidateCmd(device_data, cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
 
     // Command pool must support graphics, compute, or transfer operations
-    auto pPool = GetCommandPoolNode(device_data, cb_node->createInfo.commandPool);
-    VkQueueFlags queue_flags = GetPhysDevProperties(device_data)->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
+    auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
+    VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
     if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyBufferToImage-commandBuffer-cmdpool",
@@ -4675,15 +4991,15 @@
     skip |= ValidateImageUsageFlags(device_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
                                     "VUID-vkCmdCopyBufferToImage-dstImage-00177", "vkCmdCopyBufferToImage()",
                                     "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
-    if (GetApiVersion(device_data) >= VK_API_VERSION_1_1 || GetDeviceExtensions(device_data)->vk_khr_maintenance1) {
+    if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
         skip |= ValidateImageFormatFeatureFlags(device_data, dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
                                                 "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-dstImage-01997",
                                                 "VUID-vkCmdCopyBufferToImage-dstImage-01997");
     }
     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-renderpass");
     bool hit_error = false;
-    const std::string dst_invalid_layout_vuid =
-        (dst_image_state->shared_presentable && core_validation::GetDeviceExtensions(device_data)->vk_khr_shared_presentable_image)
+    const char *dst_invalid_layout_vuid =
+        (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
             ? "VUID-vkCmdCopyBufferToImage-dstImageLayout-01396"
             : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00181";
     for (uint32_t i = 0; i < regionCount; ++i) {
@@ -4705,19 +5021,26 @@
     return skip;
 }
 
-void PreCallRecordCmdCopyBufferToImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buffer_state,
-                                       IMAGE_STATE *dst_image_state, uint32_t region_count, const VkBufferImageCopy *regions,
-                                       VkImageLayout dst_image_layout) {
+void CoreChecks::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
+                                                   VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                   const VkBufferImageCopy *pRegions) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_node = GetCBNode(commandBuffer);
+    auto src_buffer_state = GetBufferState(srcBuffer);
+    auto dst_image_state = GetImageState(dstImage);
+
     // Make sure that all image slices are updated to correct layout
-    for (uint32_t i = 0; i < region_count; ++i) {
-        SetImageLayout(device_data, cb_node, dst_image_state, regions[i].imageSubresource, dst_image_layout);
+    for (uint32_t i = 0; i < regionCount; ++i) {
+        SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
     }
     AddCommandBufferBindingBuffer(device_data, cb_node, src_buffer_state);
     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
 }
 
-bool PreCallValidateGetImageSubresourceLayout(layer_data *device_data, VkImage image, const VkImageSubresource *pSubresource) {
-    const auto report_data = core_validation::GetReportData(device_data);
+bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
+                                                          VkSubresourceLayout *pLayout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    const auto report_data = device_data->report_data;
     bool skip = false;
     const VkImageAspectFlags sub_aspect = pSubresource->aspectMask;
 
@@ -4730,7 +5053,7 @@
                         "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set.");
     }
 
-    IMAGE_STATE *image_entry = GetImageState(device_data, image);
+    IMAGE_STATE *image_entry = GetImageState(image);
     if (!image_entry) {
         return skip;
     }
@@ -4762,7 +5085,7 @@
     const VkFormat img_format = image_entry->createInfo.format;
     if (FormatIsMultiplane(img_format)) {
         VkImageAspectFlags allowed_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
-        std::string vuid = "VUID-vkGetImageSubresourceLayout-format-01581";  // 2-plane version
+        const char *vuid = "VUID-vkGetImageSubresourceLayout-format-01581";  // 2-plane version
         if (FormatPlaneCount(img_format) > 2u) {
             allowed_flags |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
             vuid = "VUID-vkGetImageSubresourceLayout-format-01582";  // 3-plane version
@@ -4789,5 +5112,10 @@
                             "either VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT.");
         }
     }
+
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        skip |= ValidateGetImageSubresourceLayoutANDROID(device_data, image);
+    }
+
     return skip;
 }
diff --git a/layers/buffer_validation.h b/layers/buffer_validation.h
index 9878978..d3abb71 100644
--- a/layers/buffer_validation.h
+++ b/layers/buffer_validation.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2017 The Khronos Group Inc.
- * Copyright (c) 2015-2017 Valve Corporation
- * Copyright (c) 2015-2017 LunarG, Inc.
- * Copyright (C) 2015-2017 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,13 +16,11 @@
  * limitations under the License.
  *
  * Mark Lobodzinski <mark@lunarg.com>
+ * Dave Houlton <daveh@lunarg.com>
  */
 #ifndef CORE_VALIDATION_BUFFER_VALIDATION_H_
 #define CORE_VALIDATION_BUFFER_VALIDATION_H_
 
-#include "core_validation_types.h"
-#include "core_validation_error_enums.h"
-#include "descriptor_sets.h"
 #include "vulkan/vk_layer.h"
 #include <limits.h>
 #include <memory>
@@ -32,265 +30,21 @@
 #include <algorithm>
 #include <bitset>
 
-using core_validation::layer_data;
+class CoreChecks;
+typedef CoreChecks layer_data;
 
-bool PreCallValidateCreateImage(layer_data *device_data, const VkImageCreateInfo *pCreateInfo,
-                                const VkAllocationCallbacks *pAllocator, VkImage *pImage);
-
-void PostCallRecordCreateImage(layer_data *device_data, const VkImageCreateInfo *pCreateInfo, VkImage *pImage);
-
-void PreCallRecordDestroyImage(layer_data *device_data, VkImage image, IMAGE_STATE *image_state, VK_OBJECT obj_struct);
-
-bool PreCallValidateDestroyImage(layer_data *device_data, VkImage image, IMAGE_STATE **image_state, VK_OBJECT *obj_struct);
-
-bool ValidateImageAttributes(layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range);
+uint32_t FullMipChainLevels(uint32_t height, uint32_t width = 1, uint32_t depth = 1);
+uint32_t FullMipChainLevels(VkExtent3D);
+uint32_t FullMipChainLevels(VkExtent2D);
 
 uint32_t ResolveRemainingLevels(const VkImageSubresourceRange *range, uint32_t mip_levels);
 
 uint32_t ResolveRemainingLayers(const VkImageSubresourceRange *range, uint32_t layers);
 
-bool VerifyClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state,
-                            VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name);
-
-bool VerifyImageLayout(layer_data const *device_data, GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state,
-                       VkImageSubresourceLayers subLayers, VkImageLayout explicit_layout, VkImageLayout optimal_layout,
-                       const char *caller, const std::string &layout_invalid_msg_code, const std::string &layout_mismatch_msg_code,
-                       bool *error);
-
-void RecordClearImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
-                            VkImageLayout dest_image_layout);
-
-bool PreCallValidateCmdClearColorImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                       VkImageLayout imageLayout, uint32_t rangeCount, const VkImageSubresourceRange *pRanges);
-
-void PreCallRecordCmdClearImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
-                                uint32_t rangeCount, const VkImageSubresourceRange *pRanges);
-
-bool PreCallValidateCmdClearDepthStencilImage(layer_data *dev_data, VkCommandBuffer commandBuffer, VkImage image,
-                                              VkImageLayout imageLayout, uint32_t rangeCount,
-                                              const VkImageSubresourceRange *pRanges);
-
-bool FindLayoutVerifyNode(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, ImageSubresourcePair imgpair,
-                          IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask);
-
-bool FindLayoutVerifyLayout(layer_data const *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
-                            const VkImageAspectFlags aspectMask);
-
-bool FindCmdBufLayout(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, VkImage image, VkImageSubresource range,
-                      IMAGE_CMD_BUF_LAYOUT_NODE &node);
-
-bool FindGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout);
-
-bool FindLayouts(layer_data *device_data, VkImage image, std::vector<VkImageLayout> &layouts);
-
 bool FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap, ImageSubresourcePair imgpair,
                 VkImageLayout &layout, const VkImageAspectFlags aspectMask);
 
-bool FindLayout(layer_data *device_data, const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
-                ImageSubresourcePair imgpair, VkImageLayout &layout);
-
-void SetGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, const VkImageLayout &layout);
-
-void SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node);
-
-void SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout);
-
 void SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap, ImageSubresourcePair imgpair,
                VkImageLayout layout);
 
-void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout);
-void SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state,
-                        const VkImageLayout &layout);
-
-bool VerifyFramebufferAndRenderPassLayouts(layer_data *dev_data, RenderPassCreateVersion rp_version, GLOBAL_CB_NODE *pCB,
-                                           const VkRenderPassBeginInfo *pRenderPassBegin,
-                                           const FRAMEBUFFER_STATE *framebuffer_state);
-
-void TransitionAttachmentRefLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
-                                   const safe_VkAttachmentReference2KHR &ref);
-
-void TransitionSubpassLayouts(layer_data *, GLOBAL_CB_NODE *, const RENDER_PASS_STATE *, const int, FRAMEBUFFER_STATE *);
-
-void TransitionBeginRenderPassLayouts(layer_data *, GLOBAL_CB_NODE *, const RENDER_PASS_STATE *, FRAMEBUFFER_STATE *);
-
-bool ValidateImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier,
-                               uint32_t level, uint32_t layer, VkImageAspectFlags aspect);
-
-void TransitionImageAspectLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier, uint32_t level,
-                                 uint32_t layer, VkImageAspectFlags aspect);
-
-bool ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier, bool new_not_old,
-                                       VkImageUsageFlags usage, const char *func_name);
-
-bool ValidateBarriersToImages(layer_data *device_data, GLOBAL_CB_NODE const *cb_state, uint32_t imageMemoryBarrierCount,
-                              const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name);
-
-bool ValidateBarriersQFOTransferUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
-                                           uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
-                                           uint32_t imageMemBarrierCount, const VkImageMemoryBarrier *pImageMemBarriers);
-
-void RecordBarriersQFOTransfers(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
-                                uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
-                                uint32_t imageMemBarrierCount, const VkImageMemoryBarrier *pImageMemBarriers);
-
-bool ValidateQueuedQFOTransfers(layer_data *dev_data, GLOBAL_CB_NODE *pCB,
-                                QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
-                                QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards);
-
-void RecordQueuedQFOTransfers(layer_data *dev_data, GLOBAL_CB_NODE *pCB);
-void EraseQFOImageRelaseBarriers(layer_data *device_data, const VkImage &image);
-
-void TransitionImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t memBarrierCount,
-                            const VkImageMemoryBarrier *pImgMemBarriers);
-
-bool VerifySourceImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage srcImage, VkImageSubresourceLayers subLayers,
-                             VkImageLayout srcImageLayout, const std::string &msgCode);
-
-bool VerifyDestImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage destImage, VkImageSubresourceLayers subLayers,
-                           VkImageLayout destImageLayout, const std::string &msgCode);
-
-void TransitionFinalSubpassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
-                                   FRAMEBUFFER_STATE *framebuffer_state);
-
-bool PreCallValidateCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                 IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions,
-                                 VkImageLayout src_image_layout, VkImageLayout dst_image_layout);
-
-bool PreCallValidateCmdClearAttachments(layer_data *device_data, VkCommandBuffer commandBuffer, uint32_t attachmentCount,
-                                        const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects);
-
-bool PreCallValidateCmdResolveImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                    VkImageLayout src_image_layout, IMAGE_STATE *dst_image_state, VkImageLayout dst_image_layout,
-                                    uint32_t regionCount, const VkImageResolve *pRegions);
-
-void PreCallRecordCmdResolveImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                  IMAGE_STATE *dst_image_state);
-
-bool PreCallValidateCmdBlitImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                 IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageBlit *regions,
-                                 VkImageLayout src_image_layout, VkImageLayout dst_image_layout, VkFilter filter);
-
-void PreCallRecordCmdBlitImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                               IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageBlit *regions,
-                               VkImageLayout src_image_layout, VkImageLayout dst_image_layout);
-
-bool ValidateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
-                                std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const &globalImageLayoutMap,
-                                std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &overlayLayoutMap);
-
-void UpdateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB);
-
-bool ValidateMaskBitsFromLayouts(core_validation::layer_data *device_data, VkCommandBuffer cmdBuffer,
-                                 const VkAccessFlags &accessMask, const VkImageLayout &layout, const char *type);
-
-bool ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
-                                           const VkImageLayout first_layout, const uint32_t attachment,
-                                           const VkAttachmentDescription2KHR &attachment_description);
-
-bool ValidateLayouts(const core_validation::layer_data *dev_data, RenderPassCreateVersion rp_version, VkDevice device,
-                     const VkRenderPassCreateInfo2KHR *pCreateInfo);
-
-bool ValidateMapImageLayouts(core_validation::layer_data *dev_data, VkDevice device, DEVICE_MEM_INFO const *mem_info,
-                             VkDeviceSize offset, VkDeviceSize end_offset);
-
-bool ValidateImageUsageFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFlags desired, bool strict,
-                             const std::string &msgCode, char const *func_name, char const *usage_string);
-
-bool ValidateImageFormatFeatureFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
-                                     char const *func_name, const std::string &linear_vuid, const std::string &optimal_vuid);
-
-bool ValidateImageSubresourceLayers(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
-                                    const VkImageSubresourceLayers *subresource_layers, char const *func_name, char const *member,
-                                    uint32_t i);
-
-bool ValidateBufferUsageFlags(const layer_data *dev_data, BUFFER_STATE const *buffer_state, VkFlags desired, bool strict,
-                              const std::string &msgCode, char const *func_name, char const *usage_string);
-
-bool PreCallValidateCreateBuffer(layer_data *dev_data, const VkBufferCreateInfo *pCreateInfo);
-
-void PostCallRecordCreateBuffer(layer_data *device_data, const VkBufferCreateInfo *pCreateInfo, VkBuffer *pBuffer);
-
-bool PreCallValidateCreateBufferView(const layer_data *dev_data, const VkBufferViewCreateInfo *pCreateInfo);
-
-void PostCallRecordCreateBufferView(layer_data *device_data, const VkBufferViewCreateInfo *pCreateInfo, VkBufferView *pView);
-
-bool ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask,
-                             const char *func_name, const char *vuid = "VUID-VkImageSubresource-aspectMask-parameter");
-
-bool ValidateCreateImageViewSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                             bool is_imageview_2d_type, const VkImageSubresourceRange &subresourceRange);
-
-bool ValidateCmdClearColorSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                           const VkImageSubresourceRange &subresourceRange, const char *param_name);
-
-bool ValidateCmdClearDepthSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                           const VkImageSubresourceRange &subresourceRange, const char *param_name);
-
-bool ValidateImageBarrierSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
-                                          const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
-                                          const char *param_name);
-
-bool PreCallValidateCreateImageView(layer_data *device_data, const VkImageViewCreateInfo *create_info);
-
-void PostCallRecordCreateImageView(layer_data *device_data, const VkImageViewCreateInfo *create_info, VkImageView view);
-
-bool ValidateCopyBufferImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
-                                                            const IMAGE_STATE *img, const VkBufferImageCopy *region,
-                                                            const uint32_t i, const char *function, const std::string &vuid);
-
-bool ValidateImageMipLevel(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img, uint32_t mip_level,
-                           const uint32_t i, const char *function, const char *member, const std::string &vuid);
-
-bool ValidateImageArrayLayerRange(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
-                                  const uint32_t base_layer, const uint32_t layer_count, const uint32_t i, const char *function,
-                                  const char *member, const std::string &vuid);
-
-void PreCallRecordCmdCopyImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                               IMAGE_STATE *dst_image_state, uint32_t region_count, const VkImageCopy *regions,
-                               VkImageLayout src_image_layout, VkImageLayout dst_image_layout);
-
-bool PreCallValidateCmdCopyBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buffer_state,
-                                  BUFFER_STATE *dst_buffer_state);
-
-void PreCallRecordCmdCopyBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buffer_state,
-                                BUFFER_STATE *dst_buffer_state);
-
-bool PreCallValidateDestroyImageView(layer_data *device_data, VkImageView image_view, IMAGE_VIEW_STATE **image_view_state,
-                                     VK_OBJECT *obj_struct);
-
-void PreCallRecordDestroyImageView(layer_data *device_data, VkImageView image_view, IMAGE_VIEW_STATE *image_view_state,
-                                   VK_OBJECT obj_struct);
-
-bool PreCallValidateDestroyBuffer(layer_data *device_data, VkBuffer buffer, BUFFER_STATE **buffer_state, VK_OBJECT *obj_struct);
-
-void PreCallRecordDestroyBuffer(layer_data *device_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VK_OBJECT obj_struct);
-
-bool PreCallValidateDestroyBufferView(layer_data *device_data, VkBufferView buffer_view, BUFFER_VIEW_STATE **buffer_view_state,
-                                      VK_OBJECT *obj_struct);
-
-void PreCallRecordDestroyBufferView(layer_data *device_data, VkBufferView buffer_view, BUFFER_VIEW_STATE *buffer_view_state,
-                                    VK_OBJECT obj_struct);
-
-bool PreCallValidateCmdFillBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state);
-
-void PreCallRecordCmdFillBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state);
-
-bool PreCallValidateCmdCopyImageToBuffer(layer_data *device_data, VkImageLayout srcImageLayout, GLOBAL_CB_NODE *cb_node,
-                                         IMAGE_STATE *src_image_state, BUFFER_STATE *dst_buff_state, uint32_t regionCount,
-                                         const VkBufferImageCopy *pRegions, const char *func_name);
-
-void PreCallRecordCmdCopyImageToBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *src_image_state,
-                                       BUFFER_STATE *dst_buff_state, uint32_t region_count, const VkBufferImageCopy *regions,
-                                       VkImageLayout src_image_layout);
-
-bool PreCallValidateCmdCopyBufferToImage(layer_data *dev_data, VkImageLayout dstImageLayout, GLOBAL_CB_NODE *cb_node,
-                                         BUFFER_STATE *src_buff_state, IMAGE_STATE *dst_image_state, uint32_t regionCount,
-                                         const VkBufferImageCopy *pRegions, const char *func_name);
-
-void PreCallRecordCmdCopyBufferToImage(layer_data *device_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *src_buff_state,
-                                       IMAGE_STATE *dst_image_state, uint32_t region_count, const VkBufferImageCopy *regions,
-                                       VkImageLayout dst_image_layout);
-
-bool PreCallValidateGetImageSubresourceLayout(layer_data *device_data, VkImage image, const VkImageSubresource *pSubresource);
-
 #endif  // CORE_VALIDATION_BUFFER_VALIDATION_H_
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 1af98db..d33dc03 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@
  * Author: Mike Schuchardt <mikes@lunarg.com>
  * Author: Mike Weiblen <mikew@lunarg.com>
  * Author: Tony Barbour <tony@LunarG.com>
+ * Author: John Zulauf <jzulauf@lunarg.com>
+ * Author: Shannon McPherson <shannon@lunarg.com>
  */
 
 // Allow use of STL min and max functions in Windows
@@ -39,6 +41,7 @@
 #include <algorithm>
 #include <array>
 #include <assert.h>
+#include <cmath>
 #include <iostream>
 #include <list>
 #include <map>
@@ -61,32 +64,12 @@
 #if defined(__GNUC__)
 #pragma GCC diagnostic warning "-Wwrite-strings"
 #endif
+#include "chassis.h"
 #include "convert_to_renderpass2.h"
 #include "core_validation.h"
 #include "buffer_validation.h"
 #include "shader_validation.h"
-#include "vk_layer_data.h"
-#include "vk_layer_extension_utils.h"
 #include "vk_layer_utils.h"
-#include "vk_typemap_helper.h"
-
-#if defined __ANDROID__
-#include <android/log.h>
-#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "CORE_VALIDATION", __VA_ARGS__))
-#else
-#define LOGCONSOLE(...)      \
-    {                        \
-        printf(__VA_ARGS__); \
-        printf("\n");        \
-    }
-#endif
-
-// This intentionally includes a cpp file
-#include "vk_safe_struct.cpp"
-
-using mutex_t = std::mutex;
-using lock_guard_t = std::lock_guard<mutex_t>;
-using unique_lock_t = std::unique_lock<mutex_t>;
 
 // These functions are defined *outside* the core_validation namespace as their type
 // is also defined outside that namespace
@@ -124,8 +107,6 @@
     return true;
 }
 
-namespace core_validation {
-
 using std::max;
 using std::string;
 using std::stringstream;
@@ -140,279 +121,180 @@
 // 2nd special memory handle used to flag object as unbound from memory
 static const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
 
-struct instance_layer_data {
-    VkInstance instance = VK_NULL_HANDLE;
-    debug_report_data *report_data = nullptr;
-    vector<VkDebugReportCallbackEXT> logging_callback;
-    vector<VkDebugUtilsMessengerEXT> logging_messenger;
-    VkLayerInstanceDispatchTable dispatch_table;
-
-    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
-    uint32_t physical_devices_count = 0;
-    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
-    uint32_t physical_device_groups_count = 0;
-    CHECK_DISABLED disabled = {};
-
-    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
-    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
-
-    InstanceExtensions extensions;
-    uint32_t api_version;
-};
-
-struct layer_data {
-    debug_report_data *report_data = nullptr;
-    VkLayerDispatchTable dispatch_table;
-
-    DeviceExtensions extensions = {};
-    unordered_set<VkQueue> queues;  // All queues under given device
-    // Layer specific data
-    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
-    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
-    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
-    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
-    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
-    unordered_map<VkPipeline, unique_ptr<PIPELINE_STATE>> pipelineMap;
-    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
-    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
-    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
-    unordered_map<VkDescriptorSetLayout, std::shared_ptr<cvdescriptorset::DescriptorSetLayout>> descriptorSetLayoutMap;
-    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
-    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
-    unordered_map<VkFence, FENCE_NODE> fenceMap;
-    unordered_map<VkQueue, QUEUE_STATE> queueMap;
-    unordered_map<VkEvent, EVENT_STATE> eventMap;
-    unordered_map<QueryObject, bool> queryToStateMap;
-    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
-    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
-    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
-    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
-    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
-    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
-    unordered_map<VkRenderPass, std::shared_ptr<RENDER_PASS_STATE>> renderPassMap;
-    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
-    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
-    unordered_map<VkSwapchainKHR, std::unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
-    GlobalQFOTransferBarrierMap<VkImageMemoryBarrier> qfo_release_image_barrier_map;
-    GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier> qfo_release_buffer_barrier_map;
-
-    VkDevice device = VK_NULL_HANDLE;
-    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
-
-    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
-
-    DeviceFeatures enabled_features = {};
-    // Device specific data
-    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
-    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
-    VkPhysicalDeviceProperties phys_dev_props = {};
-    // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain
-    struct DeviceExtensionProperties {
-        uint32_t max_push_descriptors;  // from VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors
-        VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_props;
-        VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
-        VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
-        VkPhysicalDeviceInlineUniformBlockPropertiesEXT inline_uniform_block_props;
-    };
-    DeviceExtensionProperties phys_dev_ext_props = {};
-    bool external_sync_warning = false;
-    uint32_t api_version = 0;
-};
-
-// TODO : Do we need to guard access to layer_data_map w/ lock?
-static unordered_map<void *, layer_data *> layer_data_map;
-static unordered_map<void *, instance_layer_data *> instance_layer_data_map;
-
-static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-
-static const VkLayerProperties global_layer = {
-    "VK_LAYER_LUNARG_core_validation",
-    VK_LAYER_API_VERSION,
-    1,
-    "LunarG Validation Layer",
-};
-
-static const VkExtensionProperties device_extensions[] = {
-    {VK_EXT_VALIDATION_CACHE_EXTENSION_NAME, VK_EXT_VALIDATION_CACHE_SPEC_VERSION},
-};
-
-template <class TCreateInfo>
-void ValidateLayerOrdering(const TCreateInfo &createInfo) {
-    bool foundLayer = false;
-    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
-        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
-            foundLayer = true;
-        }
-        // This has to be logged to console as we don't have a callback at this point.
-        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
-            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
-        }
+// Return buffer state ptr for specified buffer or else NULL
+BUFFER_STATE *CoreChecks::GetBufferState(VkBuffer buffer) {
+    auto buff_it = bufferMap.find(buffer);
+    if (buff_it == bufferMap.end()) {
+        return nullptr;
     }
+    return buff_it->second.get();
 }
 
-// TODO : This can be much smarter, using separate locks for separate global data
-static mutex_t global_lock;
+// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
+IMAGE_VIEW_STATE *CoreChecks::GetImageViewState(VkImageView image_view) {
+    auto iv_it = imageViewMap.find(image_view);
+    if (iv_it == imageViewMap.end()) {
+        return nullptr;
+    }
+    return iv_it->second.get();
+}
 
 // Get the global map of pending releases
-GlobalQFOTransferBarrierMap<VkImageMemoryBarrier> &GetGlobalQFOReleaseBarrierMap(
-    layer_data *dev_data, const QFOTransferBarrier<VkImageMemoryBarrier>::Tag &type_tag) {
-    return dev_data->qfo_release_image_barrier_map;
+GlobalQFOTransferBarrierMap<VkImageMemoryBarrier> &CoreChecks::GetGlobalQFOReleaseBarrierMap(
+    const QFOTransferBarrier<VkImageMemoryBarrier>::Tag &type_tag) {
+    return qfo_release_image_barrier_map;
 }
-GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier> &GetGlobalQFOReleaseBarrierMap(
-    layer_data *dev_data, const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag &type_tag) {
-    return dev_data->qfo_release_buffer_barrier_map;
+GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier> &CoreChecks::GetGlobalQFOReleaseBarrierMap(
+    const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag &type_tag) {
+    return qfo_release_buffer_barrier_map;
 }
 
 // Get the image viewstate for a given framebuffer attachment
-IMAGE_VIEW_STATE *GetAttachmentImageViewState(layer_data *dev_data, FRAMEBUFFER_STATE *framebuffer, uint32_t index) {
+IMAGE_VIEW_STATE *CoreChecks::GetAttachmentImageViewState(FRAMEBUFFER_STATE *framebuffer, uint32_t index) {
     assert(framebuffer && (index < framebuffer->createInfo.attachmentCount));
 #ifdef FRAMEBUFFER_ATTACHMENT_STATE_CACHE
     return framebuffer->attachments[index].view_state;
 #else
     const VkImageView &image_view = framebuffer->createInfo.pAttachments[index];
-    return GetImageViewState(dev_data, image_view);
+    return GetImageViewState(image_view);
 #endif
 }
 
-// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
-IMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
-    auto iv_it = dev_data->imageViewMap.find(image_view);
-    if (iv_it == dev_data->imageViewMap.end()) {
-        return nullptr;
-    }
-    return iv_it->second.get();
-}
 // Return sampler node ptr for specified sampler or else NULL
-SAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
-    auto sampler_it = dev_data->samplerMap.find(sampler);
-    if (sampler_it == dev_data->samplerMap.end()) {
+SAMPLER_STATE *CoreChecks::GetSamplerState(VkSampler sampler) {
+    auto sampler_it = samplerMap.find(sampler);
+    if (sampler_it == samplerMap.end()) {
         return nullptr;
     }
     return sampler_it->second.get();
 }
 // Return image state ptr for specified image or else NULL
-IMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
-    auto img_it = dev_data->imageMap.find(image);
-    if (img_it == dev_data->imageMap.end()) {
+IMAGE_STATE *CoreChecks::GetImageState(VkImage image) {
+    auto img_it = imageMap.find(image);
+    if (img_it == imageMap.end()) {
         return nullptr;
     }
     return img_it->second.get();
 }
-// Return buffer state ptr for specified buffer or else NULL
-BUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
-    auto buff_it = dev_data->bufferMap.find(buffer);
-    if (buff_it == dev_data->bufferMap.end()) {
-        return nullptr;
-    }
-    return buff_it->second.get();
-}
 // Return swapchain node for specified swapchain or else NULL
-SWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
-    auto swp_it = dev_data->swapchainMap.find(swapchain);
-    if (swp_it == dev_data->swapchainMap.end()) {
+SWAPCHAIN_NODE *CoreChecks::GetSwapchainNode(VkSwapchainKHR swapchain) {
+    auto swp_it = swapchainMap.find(swapchain);
+    if (swp_it == swapchainMap.end()) {
         return nullptr;
     }
     return swp_it->second.get();
 }
 // Return buffer node ptr for specified buffer or else NULL
-BUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
-    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
-    if (bv_it == dev_data->bufferViewMap.end()) {
+BUFFER_VIEW_STATE *CoreChecks::GetBufferViewState(VkBufferView buffer_view) {
+    auto bv_it = bufferViewMap.find(buffer_view);
+    if (bv_it == bufferViewMap.end()) {
         return nullptr;
     }
     return bv_it->second.get();
 }
 
-FENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
-    auto it = dev_data->fenceMap.find(fence);
-    if (it == dev_data->fenceMap.end()) {
+FENCE_NODE *CoreChecks::GetFenceNode(VkFence fence) {
+    auto it = fenceMap.find(fence);
+    if (it == fenceMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-EVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
-    auto it = dev_data->eventMap.find(event);
-    if (it == dev_data->eventMap.end()) {
+EVENT_STATE *CoreChecks::GetEventNode(VkEvent event) {
+    auto it = eventMap.find(event);
+    if (it == eventMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-QUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
-    auto it = dev_data->queryPoolMap.find(query_pool);
-    if (it == dev_data->queryPoolMap.end()) {
+QUERY_POOL_NODE *CoreChecks::GetQueryPoolNode(VkQueryPool query_pool) {
+    auto it = queryPoolMap.find(query_pool);
+    if (it == queryPoolMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-QUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
-    auto it = dev_data->queueMap.find(queue);
-    if (it == dev_data->queueMap.end()) {
+QUEUE_STATE *CoreChecks::GetQueueState(VkQueue queue) {
+    auto it = queueMap.find(queue);
+    if (it == queueMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-SEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
-    auto it = dev_data->semaphoreMap.find(semaphore);
-    if (it == dev_data->semaphoreMap.end()) {
+SEMAPHORE_NODE *CoreChecks::GetSemaphoreNode(VkSemaphore semaphore) {
+    auto it = semaphoreMap.find(semaphore);
+    if (it == semaphoreMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-COMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
-    auto it = dev_data->commandPoolMap.find(pool);
-    if (it == dev_data->commandPoolMap.end()) {
+COMMAND_POOL_NODE *CoreChecks::GetCommandPoolNode(VkCommandPool pool) {
+    auto it = commandPoolMap.find(pool);
+    if (it == commandPoolMap.end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-PHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
-    auto it = instance_data->physical_device_map.find(phys);
-    if (it == instance_data->physical_device_map.end()) {
+PHYSICAL_DEVICE_STATE *CoreChecks::GetPhysicalDeviceState(VkPhysicalDevice phys) {
+    auto *phys_dev_map = ((physical_device_map.size() > 0) ? &physical_device_map : &instance_state->physical_device_map);
+    auto it = phys_dev_map->find(phys);
+    if (it == phys_dev_map->end()) {
         return nullptr;
     }
     return &it->second;
 }
 
-SURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
-    auto it = instance_data->surface_map.find(surface);
-    if (it == instance_data->surface_map.end()) {
+PHYSICAL_DEVICE_STATE *CoreChecks::GetPhysicalDeviceState() { return physical_device_state; }
+
+SURFACE_STATE *CoreChecks::GetSurfaceState(VkSurfaceKHR surface) {
+    auto *surf_map = ((surface_map.size() > 0) ? &surface_map : &instance_state->surface_map);
+    auto it = surf_map->find(surface);
+    if (it == surf_map->end()) {
         return nullptr;
     }
     return &it->second;
 }
 
 // Return ptr to memory binding for given handle of specified type
-static BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
+BINDABLE *CoreChecks::GetObjectMemBinding(uint64_t handle, VulkanObjectType type) {
     switch (type) {
         case kVulkanObjectTypeImage:
-            return GetImageState(dev_data, VkImage(handle));
+            return GetImageState(VkImage(handle));
         case kVulkanObjectTypeBuffer:
-            return GetBufferState(dev_data, VkBuffer(handle));
+            return GetBufferState(VkBuffer(handle));
         default:
             break;
     }
     return nullptr;
 }
+
+std::unordered_map<VkSamplerYcbcrConversion, uint64_t> *CoreChecks::GetYcbcrConversionFormatMap() {
+    return &ycbcr_conversion_ahb_fmt_map;
+}
+
+std::unordered_set<uint64_t> *CoreChecks::GetAHBExternalFormatsSet() { return &ahb_ext_formats_set; }
+
 // prototype
 GLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
 
 // Return ptr to info in map container containing mem, or NULL if not found
 //  Calls to this function should be wrapped in mutex
-DEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
-    auto mem_it = dev_data->memObjMap.find(mem);
-    if (mem_it == dev_data->memObjMap.end()) {
+DEVICE_MEM_INFO *CoreChecks::GetMemObjInfo(const VkDeviceMemory mem) {
+    auto mem_it = memObjMap.find(mem);
+    if (mem_it == memObjMap.end()) {
         return NULL;
     }
     return mem_it->second.get();
 }
 
-static void AddMemObjInfo(layer_data *dev_data, void *object, const VkDeviceMemory mem, const VkMemoryAllocateInfo *pAllocateInfo) {
+void CoreChecks::AddMemObjInfo(layer_data *dev_data, void *object, const VkDeviceMemory mem,
+                               const VkMemoryAllocateInfo *pAllocateInfo) {
     assert(object != NULL);
 
     auto *mem_info = new DEVICE_MEM_INFO(object, mem, pAllocateInfo);
@@ -424,21 +306,26 @@
         mem_info->dedicated_buffer = dedicated->buffer;
         mem_info->dedicated_image = dedicated->image;
     }
+    auto export_info = lvl_find_in_chain<VkExportMemoryAllocateInfo>(pAllocateInfo->pNext);
+    if (export_info) {
+        mem_info->is_export = true;
+        mem_info->export_handle_type_flags = export_info->handleTypes;
+    }
 }
 
 // Create binding link between given sampler and command buffer node
-void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
+void CoreChecks::AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
     sampler_state->cb_bindings.insert(cb_node);
     cb_node->object_bindings.insert({HandleToUint64(sampler_state->sampler), kVulkanObjectTypeSampler});
 }
 
 // Create binding link between given image node and command buffer node
-void AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
+void CoreChecks::AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
     // Skip validation if this image was created through WSI
     if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
         // First update CB binding in MemObj mini CB list
         for (auto mem_binding : image_state->GetBoundMemory()) {
-            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
+            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(mem_binding);
             if (pMemInfo) {
                 pMemInfo->cb_bindings.insert(cb_node);
                 // Now update CBInfo's Mem reference list
@@ -452,11 +339,12 @@
 }
 
 // Create binding link between given image view node and its image with command buffer node
-void AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
+void CoreChecks::AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node,
+                                                  IMAGE_VIEW_STATE *view_state) {
     // First add bindings for imageView
     view_state->cb_bindings.insert(cb_node);
     cb_node->object_bindings.insert({HandleToUint64(view_state->image_view), kVulkanObjectTypeImageView});
-    auto image_state = GetImageState(dev_data, view_state->create_info.image);
+    auto image_state = GetImageState(view_state->create_info.image);
     // Add bindings for image within imageView
     if (image_state) {
         AddCommandBufferBindingImage(dev_data, cb_node, image_state);
@@ -464,10 +352,10 @@
 }
 
 // Create binding link between given buffer node and command buffer node
-void AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
+void CoreChecks::AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
     // First update CB binding in MemObj mini CB list
     for (auto mem_binding : buffer_state->GetBoundMemory()) {
-        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
+        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(mem_binding);
         if (pMemInfo) {
             pMemInfo->cb_bindings.insert(cb_node);
             // Now update CBInfo's Mem reference list
@@ -480,11 +368,12 @@
 }
 
 // Create binding link between given buffer view node and its buffer with command buffer node
-void AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
+void CoreChecks::AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node,
+                                                   BUFFER_VIEW_STATE *view_state) {
     // First add bindings for bufferView
     view_state->cb_bindings.insert(cb_node);
     cb_node->object_bindings.insert({HandleToUint64(view_state->buffer_view), kVulkanObjectTypeBufferView});
-    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
+    auto buffer_state = GetBufferState(view_state->create_info.buffer);
     // Add bindings for buffer within bufferView
     if (buffer_state) {
         AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
@@ -492,11 +381,11 @@
 }
 
 // For every mem obj bound to particular CB, free bindings related to that CB
-static void ClearCmdBufAndMemReferences(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void CoreChecks::ClearCmdBufAndMemReferences(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     if (cb_node) {
         if (cb_node->memObjs.size() > 0) {
             for (auto mem : cb_node->memObjs) {
-                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
+                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(mem);
                 if (pInfo) {
                     pInfo->cb_bindings.erase(cb_node);
                 }
@@ -507,8 +396,8 @@
 }
 
 // Clear a single object binding from given memory object
-static void ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
-    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
+void CoreChecks::ClearMemoryObjectBinding(uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
+    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
     // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
     if (mem_info) {
         mem_info->obj_bindings.erase({handle, type});
@@ -518,14 +407,14 @@
 // ClearMemoryObjectBindings clears the binding of objects to memory
 //  For the given object it pulls the memory bindings and makes sure that the bindings
 //  no longer refer to the object being cleared. This occurs when objects are destroyed.
-void ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
-    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
+void CoreChecks::ClearMemoryObjectBindings(uint64_t handle, VulkanObjectType type) {
+    BINDABLE *mem_binding = GetObjectMemBinding(handle, type);
     if (mem_binding) {
         if (!mem_binding->sparse) {
-            ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
+            ClearMemoryObjectBinding(handle, type, mem_binding->binding.mem);
         } else {  // Sparse, clear all bindings
             for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
-                ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
+                ClearMemoryObjectBinding(handle, type, sparse_mem_binding.mem);
             }
         }
     }
@@ -533,27 +422,26 @@
 
 // For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
 bool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
-                              const char *type_name, std::string error_code) {
+                              const char *type_name, const char *error_code) {
     bool result = false;
     if (VK_NULL_HANDLE == mem) {
         result =
             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle, error_code,
-                    "%s: Vk%s object 0x%" PRIx64 " used with no memory bound. Memory should be bound by calling vkBind%sMemory().",
-                    api_name, type_name, handle, type_name);
+                    "%s: Vk%s object %s used with no memory bound. Memory should be bound by calling vkBind%sMemory().", api_name,
+                    type_name, dev_data->report_data->FormatHandle(handle).c_str(), type_name);
     } else if (MEMORY_UNBOUND == mem) {
         result =
             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle, error_code,
-                    "%s: Vk%s object 0x%" PRIx64
-                    " used with no memory bound and previously bound memory was freed. Memory must not be freed prior to this "
-                    "operation.",
-                    api_name, type_name, handle);
+                    "%s: Vk%s object %s used with no memory bound and previously bound memory was freed. Memory must not be freed "
+                    "prior to this operation.",
+                    api_name, type_name, dev_data->report_data->FormatHandle(handle).c_str());
     }
     return result;
 }
 
 // Check to see if memory was ever bound to this image
-bool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
-                                  const std::string &error_code) {
+bool CoreChecks::ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
+                                              const char *error_code) {
     bool result = false;
     if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
         result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), api_name, "Image",
@@ -563,8 +451,8 @@
 }
 
 // Check to see if memory was bound to this buffer
-bool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
-                                   const std::string &error_code) {
+bool CoreChecks::ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
+                                               const char *error_code) {
     bool result = false;
     if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
         result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), api_name,
@@ -575,8 +463,8 @@
 
 // SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
 // Corresponding valid usage checks are in ValidateSetMemBinding().
-static void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, BINDABLE *mem_binding, VkDeviceSize memory_offset,
-                          uint64_t handle, VulkanObjectType type, const char *apiName) {
+void CoreChecks::SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, BINDABLE *mem_binding, VkDeviceSize memory_offset,
+                               uint64_t handle, VulkanObjectType type) {
     assert(mem_binding);
     mem_binding->binding.mem = mem;
     mem_binding->UpdateBoundMemorySet();  // force recreation of cached set
@@ -584,7 +472,7 @@
     mem_binding->binding.size = mem_binding->requirements.size;
 
     if (mem != VK_NULL_HANDLE) {
-        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
+        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
         if (mem_info) {
             mem_info->obj_bindings.insert({handle, type});
             // For image objects, make sure default memory state is correctly set
@@ -609,15 +497,15 @@
 //  Otherwise, add reference from objectInfo to memoryInfo
 //  Add reference off of objInfo
 // TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
-static bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
-                                  const char *apiName) {
+bool CoreChecks::ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
+                                       const char *apiName) {
     bool skip = false;
     // It's an error to bind an object to NULL memory
     if (mem != VK_NULL_HANDLE) {
-        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
+        BINDABLE *mem_binding = GetObjectMemBinding(handle, type);
         assert(mem_binding);
         if (mem_binding->sparse) {
-            std::string error_code = "VUID-vkBindImageMemory-image-01045";
+            const char *error_code = "VUID-vkBindImageMemory-image-01045";
             const char *handle_type = "IMAGE";
             if (type == kVulkanObjectTypeBuffer) {
                 error_code = "VUID-vkBindBufferMemory-buffer-01030";
@@ -627,32 +515,35 @@
             }
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                             HandleToUint64(mem), error_code,
-                            "In %s, attempting to bind memory (0x%" PRIx64 ") to object (0x%" PRIx64
-                            ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT).",
-                            apiName, HandleToUint64(mem), handle, handle_type);
+                            "In %s, attempting to bind memory (%s) to object (%s) which was created with sparse memory flags "
+                            "(VK_%s_CREATE_SPARSE_*_BIT).",
+                            apiName, dev_data->report_data->FormatHandle(mem).c_str(),
+                            dev_data->report_data->FormatHandle(handle).c_str(), handle_type);
         }
-        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
+        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
         if (mem_info) {
-            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
+            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(mem_binding->binding.mem);
             if (prev_binding) {
-                std::string error_code = "VUID-vkBindImageMemory-image-01044";
+                const char *error_code = "VUID-vkBindImageMemory-image-01044";
                 if (type == kVulkanObjectTypeBuffer) {
                     error_code = "VUID-vkBindBufferMemory-buffer-01029";
                 } else {
                     assert(type == kVulkanObjectTypeImage);
                 }
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
-                                HandleToUint64(mem), error_code,
-                                "In %s, attempting to bind memory (0x%" PRIx64 ") to object (0x%" PRIx64
-                                ") which has already been bound to mem object 0x%" PRIx64 ".",
-                                apiName, HandleToUint64(mem), handle, HandleToUint64(prev_binding->mem));
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
+                    HandleToUint64(mem), error_code,
+                    "In %s, attempting to bind memory (%s) to object (%s) which has already been bound to mem object %s.", apiName,
+                    dev_data->report_data->FormatHandle(mem).c_str(), dev_data->report_data->FormatHandle(handle).c_str(),
+                    dev_data->report_data->FormatHandle(prev_binding->mem).c_str());
             } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
                 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                                 HandleToUint64(mem), kVUID_Core_MemTrack_RebindObject,
-                                "In %s, attempting to bind memory (0x%" PRIx64 ") to object (0x%" PRIx64
-                                ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
+                                "In %s, attempting to bind memory (%s) to object (%s) which was previous bound to memory that has "
+                                "since been freed. Memory bindings are immutable in "
                                 "Vulkan so this attempt to bind to new memory is not allowed.",
-                                apiName, HandleToUint64(mem), handle);
+                                apiName, dev_data->report_data->FormatHandle(mem).c_str(),
+                                dev_data->report_data->FormatHandle(handle).c_str());
             }
         }
     }
@@ -665,17 +556,17 @@
 //  Add reference from objectInfo to memoryInfo
 //  Add reference off of object's binding info
 // Return VK_TRUE if addition is successful, VK_FALSE otherwise
-static bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
+bool CoreChecks::SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
     bool skip = VK_FALSE;
     // Handle NULL case separately, just clear previous binding & decrement reference
     if (binding.mem == VK_NULL_HANDLE) {
         // TODO : This should cause the range of the resource to be unbound according to spec
     } else {
-        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
+        BINDABLE *mem_binding = GetObjectMemBinding(handle, type);
         assert(mem_binding);
         if (mem_binding) {  // Invalid handles are reported by object tracker, but Get returns NULL for them, so avoid SEGV here
             assert(mem_binding->sparse);
-            DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
+            DEVICE_MEM_INFO *mem_info = GetMemObjInfo(binding.mem);
             if (mem_info) {
                 mem_info->obj_bindings.insert({handle, type});
                 // Need to set mem binding for this object
@@ -687,45 +578,89 @@
     return skip;
 }
 
+bool CoreChecks::ValidateDeviceQueueFamily(layer_data *device_data, uint32_t queue_family, const char *cmd_name,
+                                           const char *parameter_name, const char *error_code, bool optional = false) {
+    bool skip = false;
+    if (!optional && queue_family == VK_QUEUE_FAMILY_IGNORED) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device_data->device), error_code,
+                        "%s: %s is VK_QUEUE_FAMILY_IGNORED, but it is required to provide a valid queue family index value.",
+                        cmd_name, parameter_name);
+    } else if (device_data->queue_family_index_map.find(queue_family) == device_data->queue_family_index_map.end()) {
+        skip |=
+            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(device_data->device), error_code,
+                    "%s: %s (= %" PRIu32
+                    ") is not one of the queue families given via VkDeviceQueueCreateInfo structures when the device was created.",
+                    cmd_name, parameter_name, queue_family);
+    }
+
+    return skip;
+}
+
+bool CoreChecks::ValidateQueueFamilies(layer_data *device_data, uint32_t queue_family_count, const uint32_t *queue_families,
+                                       const char *cmd_name, const char *array_parameter_name, const char *unique_error_code,
+                                       const char *valid_error_code, bool optional = false) {
+    bool skip = false;
+    if (queue_families) {
+        std::unordered_set<uint32_t> set;
+        for (uint32_t i = 0; i < queue_family_count; ++i) {
+            std::string parameter_name = std::string(array_parameter_name) + "[" + std::to_string(i) + "]";
+
+            if (set.count(queue_families[i])) {
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(device_data->device), unique_error_code,
+                                "%s: %s (=%" PRIu32 ") is not unique within %s array.", cmd_name, parameter_name.c_str(),
+                                queue_families[i], array_parameter_name);
+            } else {
+                set.insert(queue_families[i]);
+                skip |= ValidateDeviceQueueFamily(device_data, queue_families[i], cmd_name, parameter_name.c_str(),
+                                                  valid_error_code, optional);
+            }
+        }
+    }
+    return skip;
+}
+
 // Check object status for selected flag state
-static bool ValidateStatus(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
-                           const char *fail_msg, std::string const msg_code) {
+bool CoreChecks::ValidateStatus(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
+                                const char *fail_msg, const char *msg_code) {
     if (!(pNode->status & status_mask)) {
         return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                       HandleToUint64(pNode->commandBuffer), msg_code, "command buffer object 0x%" PRIx64 ": %s..",
-                       HandleToUint64(pNode->commandBuffer), fail_msg);
+                       HandleToUint64(pNode->commandBuffer), msg_code, "command buffer object %s: %s..",
+                       dev_data->report_data->FormatHandle(pNode->commandBuffer).c_str(), fail_msg);
     }
     return false;
 }
 
 // Retrieve pipeline node ptr for given pipeline object
-static PIPELINE_STATE *GetPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
-    auto it = dev_data->pipelineMap.find(pipeline);
-    if (it == dev_data->pipelineMap.end()) {
+PIPELINE_STATE *CoreChecks::GetPipelineState(VkPipeline pipeline) {
+    auto it = pipelineMap.find(pipeline);
+    if (it == pipelineMap.end()) {
         return nullptr;
     }
     return it->second.get();
 }
 
-RENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
-    auto it = dev_data->renderPassMap.find(renderpass);
-    if (it == dev_data->renderPassMap.end()) {
+RENDER_PASS_STATE *CoreChecks::GetRenderPassState(VkRenderPass renderpass) {
+    auto it = renderPassMap.find(renderpass);
+    if (it == renderPassMap.end()) {
         return nullptr;
     }
     return it->second.get();
 }
 
-std::shared_ptr<RENDER_PASS_STATE> GetRenderPassStateSharedPtr(layer_data const *dev_data, VkRenderPass renderpass) {
-    auto it = dev_data->renderPassMap.find(renderpass);
-    if (it == dev_data->renderPassMap.end()) {
+std::shared_ptr<RENDER_PASS_STATE> CoreChecks::GetRenderPassStateSharedPtr(VkRenderPass renderpass) {
+    auto it = renderPassMap.find(renderpass);
+    if (it == renderPassMap.end()) {
         return nullptr;
     }
     return it->second;
 }
 
-FRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
-    auto it = dev_data->frameBufferMap.find(framebuffer);
-    if (it == dev_data->frameBufferMap.end()) {
+FRAMEBUFFER_STATE *CoreChecks::GetFramebufferState(VkFramebuffer framebuffer) {
+    auto it = frameBufferMap.find(framebuffer);
+    if (it == frameBufferMap.end()) {
         return nullptr;
     }
     return it->second.get();
@@ -740,7 +675,7 @@
     return it->second;
 }
 
-static PIPELINE_LAYOUT_NODE const *GetPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
+PIPELINE_LAYOUT_NODE const *CoreChecks::GetPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
     auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
     if (it == dev_data->pipelineLayoutMap.end()) {
         return nullptr;
@@ -748,9 +683,18 @@
     return &it->second;
 }
 
-shader_module const *GetShaderModuleState(layer_data const *dev_data, VkShaderModule module) {
-    auto it = dev_data->shaderModuleMap.find(module);
-    if (it == dev_data->shaderModuleMap.end()) {
+shader_module const *CoreChecks::GetShaderModuleState(VkShaderModule module) {
+    auto it = shaderModuleMap.find(module);
+    if (it == shaderModuleMap.end()) {
+        return nullptr;
+    }
+    return it->second.get();
+}
+
+const TEMPLATE_STATE *CoreChecks::GetDescriptorTemplateState(const layer_data *dev_data,
+                                                             VkDescriptorUpdateTemplateKHR descriptor_update_template) {
+    const auto it = dev_data->desc_template_map.find(descriptor_update_template);
+    if (it == dev_data->desc_template_map.cend()) {
         return nullptr;
     }
     return it->second.get();
@@ -767,8 +711,8 @@
 }
 
 // Validate state stored as flags at time of draw call
-static bool ValidateDrawStateFlags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
-                                   std::string const msg_code) {
+bool CoreChecks::ValidateDrawStateFlags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
+                                        const char *msg_code) {
     bool result = false;
     if (pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
         pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) {
@@ -806,21 +750,22 @@
     return result;
 }
 
-static bool LogInvalidAttachmentMessage(layer_data const *dev_data, const char *type1_string, const RENDER_PASS_STATE *rp1_state,
-                                        const char *type2_string, const RENDER_PASS_STATE *rp2_state, uint32_t primary_attach,
-                                        uint32_t secondary_attach, const char *msg, const char *caller, std::string error_code) {
+bool CoreChecks::LogInvalidAttachmentMessage(layer_data const *dev_data, const char *type1_string,
+                                             const RENDER_PASS_STATE *rp1_state, const char *type2_string,
+                                             const RENDER_PASS_STATE *rp2_state, uint32_t primary_attach, uint32_t secondary_attach,
+                                             const char *msg, const char *caller, const char *error_code) {
     return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                    HandleToUint64(rp1_state->renderPass), error_code,
-                   "%s: RenderPasses incompatible between %s w/ renderPass 0x%" PRIx64 " and %s w/ renderPass 0x%" PRIx64
-                   " Attachment %u is not compatible with %u: %s.",
-                   caller, type1_string, HandleToUint64(rp1_state->renderPass), type2_string, HandleToUint64(rp2_state->renderPass),
-                   primary_attach, secondary_attach, msg);
+                   "%s: RenderPasses incompatible between %s w/ renderPass %s and %s w/ renderPass %s Attachment %u is not "
+                   "compatible with %u: %s.",
+                   caller, type1_string, dev_data->report_data->FormatHandle(rp1_state->renderPass).c_str(), type2_string,
+                   dev_data->report_data->FormatHandle(rp2_state->renderPass).c_str(), primary_attach, secondary_attach, msg);
 }
 
-static bool ValidateAttachmentCompatibility(layer_data const *dev_data, const char *type1_string,
-                                            const RENDER_PASS_STATE *rp1_state, const char *type2_string,
-                                            const RENDER_PASS_STATE *rp2_state, uint32_t primary_attach, uint32_t secondary_attach,
-                                            const char *caller, std::string error_code) {
+bool CoreChecks::ValidateAttachmentCompatibility(layer_data const *dev_data, const char *type1_string,
+                                                 const RENDER_PASS_STATE *rp1_state, const char *type2_string,
+                                                 const RENDER_PASS_STATE *rp2_state, uint32_t primary_attach,
+                                                 uint32_t secondary_attach, const char *caller, const char *error_code) {
     bool skip = false;
     const auto &primaryPassCI = rp1_state->createInfo;
     const auto &secondaryPassCI = rp2_state->createInfo;
@@ -859,9 +804,10 @@
     return skip;
 }
 
-static bool ValidateSubpassCompatibility(layer_data const *dev_data, const char *type1_string, const RENDER_PASS_STATE *rp1_state,
-                                         const char *type2_string, const RENDER_PASS_STATE *rp2_state, const int subpass,
-                                         const char *caller, std::string error_code) {
+bool CoreChecks::ValidateSubpassCompatibility(layer_data const *dev_data, const char *type1_string,
+                                              const RENDER_PASS_STATE *rp1_state, const char *type2_string,
+                                              const RENDER_PASS_STATE *rp2_state, const int subpass, const char *caller,
+                                              const char *error_code) {
     bool skip = false;
     const auto &primary_desc = rp1_state->createInfo.pSubpasses[subpass];
     const auto &secondary_desc = rp2_state->createInfo.pSubpasses[subpass];
@@ -888,15 +834,17 @@
         }
         skip |= ValidateAttachmentCompatibility(dev_data, type1_string, rp1_state, type2_string, rp2_state, primary_color_attach,
                                                 secondary_color_attach, caller, error_code);
-        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
-        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
-            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
+        if (rp1_state->createInfo.subpassCount > 1) {
+            uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
+            if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
+                primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
+            }
+            if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
+                secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
+            }
+            skip |= ValidateAttachmentCompatibility(dev_data, type1_string, rp1_state, type2_string, rp2_state,
+                                                    primary_resolve_attach, secondary_resolve_attach, caller, error_code);
         }
-        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
-            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
-        }
-        skip |= ValidateAttachmentCompatibility(dev_data, type1_string, rp1_state, type2_string, rp2_state, primary_resolve_attach,
-                                                secondary_resolve_attach, caller, error_code);
     }
     uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
     if (primary_desc.pDepthStencilAttachment) {
@@ -913,18 +861,19 @@
 // Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
 //  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
 //  will then feed into this function
-static bool ValidateRenderPassCompatibility(layer_data const *dev_data, const char *type1_string,
-                                            const RENDER_PASS_STATE *rp1_state, const char *type2_string,
-                                            const RENDER_PASS_STATE *rp2_state, const char *caller, std::string error_code) {
+bool CoreChecks::ValidateRenderPassCompatibility(layer_data const *dev_data, const char *type1_string,
+                                                 const RENDER_PASS_STATE *rp1_state, const char *type2_string,
+                                                 const RENDER_PASS_STATE *rp2_state, const char *caller, const char *error_code) {
     bool skip = false;
 
     if (rp1_state->createInfo.subpassCount != rp2_state->createInfo.subpassCount) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                         HandleToUint64(rp1_state->renderPass), error_code,
-                        "%s: RenderPasses incompatible between %s w/ renderPass 0x%" PRIx64
-                        " with a subpassCount of %u and %s w/ renderPass 0x%" PRIx64 " with a subpassCount of %u.",
-                        caller, type1_string, HandleToUint64(rp1_state->renderPass), rp1_state->createInfo.subpassCount,
-                        type2_string, HandleToUint64(rp2_state->renderPass), rp2_state->createInfo.subpassCount);
+                        "%s: RenderPasses incompatible between %s w/ renderPass %s with a subpassCount of %u and %s w/ renderPass "
+                        "%s with a subpassCount of %u.",
+                        caller, type1_string, dev_data->report_data->FormatHandle(rp1_state->renderPass).c_str(),
+                        rp1_state->createInfo.subpassCount, type2_string,
+                        dev_data->report_data->FormatHandle(rp2_state->renderPass).c_str(), rp2_state->createInfo.subpassCount);
     } else {
         for (uint32_t i = 0; i < rp1_state->createInfo.subpassCount; ++i) {
             skip |= ValidateSubpassCompatibility(dev_data, type1_string, rp1_state, type2_string, rp2_state, i, caller, error_code);
@@ -934,9 +883,9 @@
 }
 
 // Return Set node ptr for specified set or else NULL
-cvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
-    auto set_it = dev_data->setMap.find(set);
-    if (set_it == dev_data->setMap.end()) {
+cvdescriptorset::DescriptorSet *CoreChecks::GetSetNode(VkDescriptorSet set) {
+    auto set_it = setMap.find(set);
+    if (set_it == setMap.end()) {
         return NULL;
     }
     return set_it->second;
@@ -964,8 +913,8 @@
 }
 
 // Validate draw-time state related to the PSO
-static bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
-                                          CMD_TYPE cmd_type, PIPELINE_STATE const *pPipeline, const char *caller) {
+bool CoreChecks::ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
+                                               CMD_TYPE cmd_type, PIPELINE_STATE const *pPipeline, const char *caller) {
     bool skip = false;
 
     // Verify vertex binding
@@ -974,14 +923,13 @@
             const auto vertex_binding = pPipeline->vertex_binding_descriptions_[i].binding;
             if ((pCB->current_draw_data.vertex_buffer_bindings.size() < (vertex_binding + 1)) ||
                 (pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer == VK_NULL_HANDLE)) {
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_VtxIndexOutOfBounds,
-                            "The Pipeline State Object (0x%" PRIx64
-                            ") expects that this Command Buffer's vertex binding Index %u should be set via "
-                            "vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at "
-                            "index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
-                            HandleToUint64(state.pipeline_state->pipeline), vertex_binding, i, vertex_binding);
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_VtxIndexOutOfBounds,
+                    "The Pipeline State Object (%s) expects that this Command Buffer's vertex binding Index %u should be set via "
+                    "vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at "
+                    "index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
+                    dev_data->report_data->FormatHandle(state.pipeline_state->pipeline).c_str(), vertex_binding, i, vertex_binding);
             }
         }
 
@@ -998,23 +946,28 @@
                 (pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer != VK_NULL_HANDLE)) {
                 const auto vertex_buffer_stride = pPipeline->vertex_binding_descriptions_[vertex_binding_map_it->second].stride;
                 const auto vertex_buffer_offset = pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].offset;
-                const auto buffer_state =
-                    GetBufferState(dev_data, pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer);
+                const auto buffer_state = GetBufferState(pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer);
 
                 // Use only memory binding offset as base memory should be properly aligned by the driver
                 const auto buffer_binding_address = buffer_state->binding.offset + vertex_buffer_offset;
                 // Use 1 as vertex/instance index to use buffer stride as well
                 const auto attrib_address = buffer_binding_address + vertex_buffer_stride + attribute_offset;
 
-                if (SafeModulo(attrib_address, FormatAlignment(attribute_format)) != 0) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
-                                    HandleToUint64(pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer),
-                                    kVUID_Core_DrawState_InvalidVtxAttributeAlignment,
-                                    "Invalid attribAddress alignment for vertex attribute " PRINTF_SIZE_T_SPECIFIER
-                                    " from "
-                                    "pipeline (0x%" PRIx64 ") and vertex buffer (0x%" PRIx64 ").",
-                                    i, HandleToUint64(state.pipeline_state->pipeline),
-                                    HandleToUint64(pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer));
+                uint32_t vtx_attrib_req_alignment = FormatElementSize(attribute_format);
+                if (FormatElementIsTexel(attribute_format)) {
+                    vtx_attrib_req_alignment /= FormatChannelCount(attribute_format);
+                }
+
+                if (SafeModulo(attrib_address, vtx_attrib_req_alignment) != 0) {
+                    skip |= log_msg(
+                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                        HandleToUint64(pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer),
+                        kVUID_Core_DrawState_InvalidVtxAttributeAlignment,
+                        "Invalid attribAddress alignment for vertex attribute " PRINTF_SIZE_T_SPECIFIER
+                        " from pipeline (%s) and vertex buffer (%s).",
+                        i, dev_data->report_data->FormatHandle(state.pipeline_state->pipeline).c_str(),
+                        dev_data->report_data->FormatHandle(pCB->current_draw_data.vertex_buffer_bindings[vertex_binding].buffer)
+                            .c_str());
                 }
             }
         }
@@ -1023,9 +976,10 @@
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer),
                             kVUID_Core_DrawState_VtxIndexOutOfBounds,
-                            "Vertex buffers are bound to command buffer (0x%" PRIx64
-                            ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIx64 ").",
-                            HandleToUint64(pCB->commandBuffer), HandleToUint64(state.pipeline_state->pipeline));
+                            "Vertex buffers are bound to command buffer (%s) but no vertex buffers are attached to this Pipeline "
+                            "State Object (%s).",
+                            dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(),
+                            dev_data->report_data->FormatHandle(state.pipeline_state->pipeline).c_str());
         }
     }
 
@@ -1087,20 +1041,22 @@
                 subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
             }
 
-            if (!dev_data->extensions.vk_amd_mixed_attachment_samples &&
+            if (!(dev_data->device_extensions.vk_amd_mixed_attachment_samples ||
+                  dev_data->device_extensions.vk_nv_framebuffer_mixed_samples) &&
                 ((subpass_num_samples & static_cast<unsigned>(pso_num_samples)) != subpass_num_samples)) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
-                                HandleToUint64(pPipeline->pipeline), kVUID_Core_DrawState_NumSamplesMismatch,
-                                "Num samples mismatch! At draw-time in Pipeline (0x%" PRIx64
-                                ") with %u samples while current RenderPass (0x%" PRIx64 ") w/ %u samples!",
-                                HandleToUint64(pPipeline->pipeline), pso_num_samples,
-                                HandleToUint64(pCB->activeRenderPass->renderPass), subpass_num_samples);
+                skip |=
+                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                            HandleToUint64(pPipeline->pipeline), kVUID_Core_DrawState_NumSamplesMismatch,
+                            "Num samples mismatch! At draw-time in Pipeline (%s) with %u samples while current RenderPass (%s) w/ "
+                            "%u samples!",
+                            dev_data->report_data->FormatHandle(pPipeline->pipeline).c_str(), pso_num_samples,
+                            dev_data->report_data->FormatHandle(pCB->activeRenderPass->renderPass).c_str(), subpass_num_samples);
             }
         } else {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                             HandleToUint64(pPipeline->pipeline), kVUID_Core_DrawState_NoActiveRenderpass,
-                            "No active render pass found at draw-time in Pipeline (0x%" PRIx64 ")!",
-                            HandleToUint64(pPipeline->pipeline));
+                            "No active render pass found at draw-time in Pipeline (%s)!",
+                            dev_data->report_data->FormatHandle(pPipeline->pipeline).c_str());
         }
     }
     // Verify that PSO creation renderPass is compatible with active renderPass
@@ -1154,7 +1110,6 @@
                 assert(CMD_DRAW == cmd_type);
                 break;
         }
-        std::string err_string;
         if (pCB->activeRenderPass->renderPass != pPipeline->rp_state->renderPass) {
             // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
             skip |= ValidateRenderPassCompatibility(dev_data, "active render pass", pCB->activeRenderPass, "pipeline state object",
@@ -1191,9 +1146,9 @@
 }
 
 // Validate overall state at the time of a draw call
-static bool ValidateCmdBufDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, CMD_TYPE cmd_type, const bool indexed,
-                                    const VkPipelineBindPoint bind_point, const char *function, const std::string &pipe_err_code,
-                                    const std::string &state_err_code) {
+bool CoreChecks::ValidateCmdBufDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, CMD_TYPE cmd_type, const bool indexed,
+                                         const VkPipelineBindPoint bind_point, const char *function, const char *pipe_err_code,
+                                         const char *state_err_code) {
     bool result = false;
     auto const &state = cb_node->lastBound[bind_point];
     PIPELINE_STATE *pPipe = state.pipeline_state;
@@ -1218,16 +1173,17 @@
         if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
             result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                               HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_DescriptorSetNotBound,
-                              "VkPipeline 0x%" PRIx64 " uses set #%u but that set is not bound.", HandleToUint64(pPipe->pipeline),
-                              setIndex);
+                              "VkPipeline %s uses set #%u but that set is not bound.",
+                              dev_data->report_data->FormatHandle(pPipe->pipeline).c_str(), setIndex);
         } else if (!VerifySetLayoutCompatibility(state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex, errorString)) {
             // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
             VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
-            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                              HandleToUint64(setHandle), kVUID_Core_DrawState_PipelineLayoutsIncompatible,
-                              "VkDescriptorSet (0x%" PRIx64
-                              ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIx64 " due to: %s",
-                              HandleToUint64(setHandle), setIndex, HandleToUint64(pipeline_layout.layout), errorString.c_str());
+            result |=
+                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                        HandleToUint64(setHandle), kVUID_Core_DrawState_PipelineLayoutsIncompatible,
+                        "VkDescriptorSet (%s) bound as set #%u is not compatible with overlapping VkPipelineLayout %s due to: %s",
+                        dev_data->report_data->FormatHandle(setHandle).c_str(), setIndex,
+                        dev_data->report_data->FormatHandle(pipeline_layout.layout).c_str(), errorString.c_str());
         } else {  // Valid set is bound and layout compatible, validate that it's updated
             // Pull the set node
             cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
@@ -1248,8 +1204,8 @@
                     result |= log_msg(
                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                         HandleToUint64(set), kVUID_Core_DrawState_DescriptorSetNotUpdated,
-                        "Descriptor set 0x%" PRIx64 " bound as set #%u encountered the following validation error at %s time: %s",
-                        HandleToUint64(set), setIndex, function, err_str.c_str());
+                        "Descriptor set %s bound as set #%u encountered the following validation error at %s time: %s",
+                        dev_data->report_data->FormatHandle(set).c_str(), setIndex, function, err_str.c_str());
                 }
             }
         }
@@ -1262,7 +1218,7 @@
     return result;
 }
 
-static void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
+void CoreChecks::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
     auto const &state = cb_state->lastBound[bind_point];
     PIPELINE_STATE *pPipe = state.pipeline_state;
     if (VK_NULL_HANDLE != state.pipeline_layout) {
@@ -1287,8 +1243,8 @@
     }
 }
 
-static bool ValidatePipelineLocked(layer_data *dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const &pPipelines,
-                                   int pipelineIndex) {
+bool CoreChecks::ValidatePipelineLocked(layer_data *dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const &pPipelines,
+                                        int pipelineIndex) {
     bool skip = false;
 
     PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex].get();
@@ -1314,7 +1270,7 @@
                 pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex].get();
             }
         } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
-            pBasePipeline = GetPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
+            pBasePipeline = GetPipelineState(pPipeline->graphicsPipelineCI.basePipelineHandle);
         }
 
         if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
@@ -1328,8 +1284,8 @@
 }
 
 // UNLOCKED pipeline validation. DO NOT lookup objects in the layer_data->* maps in this function.
-static bool ValidatePipelineUnlocked(layer_data *dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const &pPipelines,
-                                     int pipelineIndex) {
+bool CoreChecks::ValidatePipelineUnlocked(layer_data *dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const &pPipelines,
+                                          int pipelineIndex) {
     bool skip = false;
 
     PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex].get();
@@ -1349,13 +1305,13 @@
     if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
         const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
         if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
-            skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
-                HandleToUint64(pPipeline->pipeline), "VUID-VkGraphicsPipelineCreateInfo-attachmentCount-00746",
-                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIx64
-                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u.",
-                HandleToUint64(pPipeline->rp_state->renderPass), pPipeline->graphicsPipelineCI.subpass,
-                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount);
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                            HandleToUint64(pPipeline->pipeline), "VUID-VkGraphicsPipelineCreateInfo-attachmentCount-00746",
+                            "vkCreateGraphicsPipelines(): Render pass (%s) subpass %u has colorAttachmentCount of %u which doesn't "
+                            "match the pColorBlendState->attachmentCount of %u.",
+                            dev_data->report_data->FormatHandle(pPipeline->rp_state->renderPass).c_str(),
+                            pPipeline->graphicsPipelineCI.subpass, subpass_desc->colorAttachmentCount,
+                            color_blend_state->attachmentCount);
         }
         if (!dev_data->enabled_features.core.independentBlend) {
             if (pPipeline->attachments.size() > 1) {
@@ -1457,7 +1413,7 @@
             }
         }
     }
-    if (dev_data->extensions.vk_nv_mesh_shader) {
+    if (dev_data->device_extensions.vk_nv_mesh_shader) {
         // VS or mesh is required
         if (!(pPipeline->active_shaders & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_MESH_BIT_NV))) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
@@ -1625,8 +1581,7 @@
             VkFormat format = vi->pVertexAttributeDescriptions[j].format;
             // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
             VkFormatProperties properties;
-            dev_data->instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(dev_data->physical_device, format,
-                                                                                      &properties);
+            dev_data->instance_dispatch_table.GetPhysicalDeviceFormatProperties(dev_data->physical_device, format, &properties);
             if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
                 skip |=
                     log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -1638,7 +1593,39 @@
         }
     }
 
-    if (dev_data->extensions.vk_amd_mixed_attachment_samples) {
+    auto accumColorSamples = [subpass_desc, pPipeline](uint32_t &samples) {
+        for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; i++) {
+            const auto attachment = subpass_desc->pColorAttachments[i].attachment;
+            if (attachment != VK_ATTACHMENT_UNUSED) {
+                samples |= static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
+            }
+        }
+    };
+
+    if (!(dev_data->device_extensions.vk_amd_mixed_attachment_samples ||
+          dev_data->device_extensions.vk_nv_framebuffer_mixed_samples)) {
+        uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
+        uint32_t subpass_num_samples = 0;
+
+        accumColorSamples(subpass_num_samples);
+
+        if (subpass_desc->pDepthStencilAttachment && subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
+            const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
+            subpass_num_samples |= static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
+        }
+
+        // subpass_num_samples is 0 when the subpass has no attachments or if all attachments are VK_ATTACHMENT_UNUSED.
+        // Only validate the value of subpass_num_samples if the subpass has attachments that are not VK_ATTACHMENT_UNUSED.
+        if (subpass_num_samples && (!IsPowerOfTwo(subpass_num_samples) || (subpass_num_samples != raster_samples))) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                            HandleToUint64(pPipeline->pipeline), "VUID-VkGraphicsPipelineCreateInfo-subpass-00757",
+                            "vkCreateGraphicsPipelines: pCreateInfo[%d].pMultisampleState->rasterizationSamples (%u) "
+                            "does not match the number of samples of the RenderPass color and/or depth attachment.",
+                            pipelineIndex, raster_samples);
+        }
+    }
+
+    if (dev_data->device_extensions.vk_amd_mixed_attachment_samples) {
         VkSampleCountFlagBits max_sample_count = static_cast<VkSampleCountFlagBits>(0);
         for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
             if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
@@ -1664,15 +1651,131 @@
         }
     }
 
+    if (dev_data->device_extensions.vk_nv_framebuffer_mixed_samples) {
+        uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
+        uint32_t subpass_color_samples = 0;
+
+        accumColorSamples(subpass_color_samples);
+
+        if (subpass_desc->pDepthStencilAttachment && subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
+            const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
+            const uint32_t subpass_depth_samples =
+                static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
+
+            if (pPipeline->graphicsPipelineCI.pDepthStencilState) {
+                const bool ds_test_enabled = (pPipeline->graphicsPipelineCI.pDepthStencilState->depthTestEnable == VK_TRUE) ||
+                                             (pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) ||
+                                             (pPipeline->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE);
+
+                if (ds_test_enabled && (!IsPowerOfTwo(subpass_depth_samples) || (raster_samples != subpass_depth_samples))) {
+                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                    HandleToUint64(pPipeline->pipeline), "VUID-VkGraphicsPipelineCreateInfo-subpass-01411",
+                                    "vkCreateGraphicsPipelines: pCreateInfo[%d].pMultisampleState->rasterizationSamples (%u) "
+                                    "does not match the number of samples of the RenderPass depth attachment (%u).",
+                                    pipelineIndex, raster_samples, subpass_depth_samples);
+                }
+            }
+        }
+
+        if (IsPowerOfTwo(subpass_color_samples)) {
+            if (raster_samples < subpass_color_samples) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pPipeline->pipeline), "VUID-VkGraphicsPipelineCreateInfo-subpass-01412",
+                                "vkCreateGraphicsPipelines: pCreateInfo[%d].pMultisampleState->rasterizationSamples (%u) "
+                                "is not greater or equal to the number of samples of the RenderPass color attachment (%u).",
+                                pipelineIndex, raster_samples, subpass_color_samples);
+            }
+
+            if (pPipeline->graphicsPipelineCI.pMultisampleState) {
+                if ((raster_samples > subpass_color_samples) &&
+                    (pPipeline->graphicsPipelineCI.pMultisampleState->sampleShadingEnable == VK_TRUE)) {
+                    skip |= log_msg(
+                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                        HandleToUint64(pPipeline->pipeline), "VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415",
+                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pMultisampleState->sampleShadingEnable must be VK_FALSE when "
+                        "pCreateInfo[%d].pMultisampleState->rasterizationSamples (%u) is greater than the number of samples of the "
+                        "subpass color attachment (%u).",
+                        pipelineIndex, pipelineIndex, raster_samples, subpass_color_samples);
+                }
+
+                const auto *coverage_modulation_state = lvl_find_in_chain<VkPipelineCoverageModulationStateCreateInfoNV>(
+                    pPipeline->graphicsPipelineCI.pMultisampleState->pNext);
+
+                if (coverage_modulation_state && (coverage_modulation_state->coverageModulationTableEnable == VK_TRUE)) {
+                    if (coverage_modulation_state->coverageModulationTableCount != (raster_samples / subpass_color_samples)) {
+                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                        VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, HandleToUint64(pPipeline->pipeline),
+                                        "VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405",
+                                        "vkCreateGraphicsPipelines: pCreateInfos[%d] VkPipelineCoverageModulationStateCreateInfoNV "
+                                        "coverageModulationTableCount of %u is invalid.",
+                                        pipelineIndex, coverage_modulation_state->coverageModulationTableCount);
+                    }
+                }
+            }
+        }
+    }
+
+    if (dev_data->device_extensions.vk_nv_fragment_coverage_to_color) {
+        const auto coverage_to_color_state =
+            lvl_find_in_chain<VkPipelineCoverageToColorStateCreateInfoNV>(pPipeline->graphicsPipelineCI.pMultisampleState);
+
+        if (coverage_to_color_state && coverage_to_color_state->coverageToColorEnable == VK_TRUE) {
+            bool attachment_is_valid = false;
+            std::string error_detail;
+
+            if (coverage_to_color_state->coverageToColorLocation < subpass_desc->colorAttachmentCount) {
+                const auto color_attachment_ref = subpass_desc->pColorAttachments[coverage_to_color_state->coverageToColorLocation];
+                if (color_attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
+                    const auto color_attachment = pPipeline->rp_state->createInfo.pAttachments[color_attachment_ref.attachment];
+
+                    switch (color_attachment.format) {
+                        case VK_FORMAT_R8_UINT:
+                        case VK_FORMAT_R8_SINT:
+                        case VK_FORMAT_R16_UINT:
+                        case VK_FORMAT_R16_SINT:
+                        case VK_FORMAT_R32_UINT:
+                        case VK_FORMAT_R32_SINT:
+                            attachment_is_valid = true;
+                            break;
+                        default:
+                            string_sprintf(&error_detail, "references an attachment with an invalid format (%s).",
+                                           string_VkFormat(color_attachment.format));
+                            break;
+                    }
+                } else {
+                    string_sprintf(&error_detail,
+                                   "references an invalid attachment. The subpass pColorAttachments[%" PRIu32
+                                   "].attachment has the value "
+                                   "VK_ATTACHMENT_UNUSED.",
+                                   coverage_to_color_state->coverageToColorLocation);
+                }
+            } else {
+                string_sprintf(&error_detail,
+                               "references an non-existing attachment since the subpass colorAttachmentCount is %" PRIu32 ".",
+                               subpass_desc->colorAttachmentCount);
+            }
+
+            if (!attachment_is_valid) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pPipeline->pipeline),
+                                "VUID-VkPipelineCoverageToColorStateCreateInfoNV-coverageToColorEnable-01404",
+                                "vkCreateGraphicsPipelines: pCreateInfos[%" PRId32
+                                "].pMultisampleState VkPipelineCoverageToColorStateCreateInfoNV "
+                                "coverageToColorLocation = %" PRIu32 " %s",
+                                pipelineIndex, coverage_to_color_state->coverageToColorLocation, error_detail.c_str());
+            }
+        }
+    }
+
     return skip;
 }
 
 // Block of code at start here specifically for managing/tracking DSs
 
 // Return Pool node ptr for specified pool or else NULL
-DESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
-    auto pool_it = dev_data->descriptorPoolMap.find(pool);
-    if (pool_it == dev_data->descriptorPoolMap.end()) {
+DESCRIPTOR_POOL_STATE *CoreChecks::GetDescriptorPoolState(const VkDescriptorPool pool) {
+    auto pool_it = descriptorPoolMap.find(pool);
+    if (pool_it == descriptorPoolMap.end()) {
         return NULL;
     }
     return pool_it->second;
@@ -1682,35 +1785,35 @@
 // func_str is the name of the calling function
 // Return false if no errors occur
 // Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
-static bool ValidateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
-    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
+bool CoreChecks::ValidateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, const char *func_str) {
+    if (dev_data->disabled.idle_descriptor_set) return false;
     bool skip = false;
     auto set_node = dev_data->setMap.find(set);
     if (set_node == dev_data->setMap.end()) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                         HandleToUint64(set), kVUID_Core_DrawState_DoubleDestroy,
-                        "Cannot call %s() on descriptor set 0x%" PRIx64 " that has not been allocated.", func_str.c_str(),
-                        HandleToUint64(set));
+                        "Cannot call %s() on descriptor set %s that has not been allocated.", func_str,
+                        dev_data->report_data->FormatHandle(set).c_str());
     } else {
         // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
         if (set_node->second->in_use.load()) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                             HandleToUint64(set), "VUID-vkFreeDescriptorSets-pDescriptorSets-00309",
-                            "Cannot call %s() on descriptor set 0x%" PRIx64 " that is in use by a command buffer.",
-                            func_str.c_str(), HandleToUint64(set));
+                            "Cannot call %s() on descriptor set %s that is in use by a command buffer.", func_str,
+                            dev_data->report_data->FormatHandle(set).c_str());
         }
     }
     return skip;
 }
 
 // Remove set from setMap and delete the set
-static void FreeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
+void CoreChecks::FreeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
     dev_data->setMap.erase(descriptor_set->GetSet());
     delete descriptor_set;
 }
 // Free all DS Pools including their Sets & related sub-structs
 // NOTE : Calls to this function should be wrapped in mutex
-static void DeletePools(layer_data *dev_data) {
+void CoreChecks::DeletePools(layer_data *dev_data) {
     for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end();) {
         // Remove this pools' sets from setMap and delete them
         for (auto ds : ii->second->sets) {
@@ -1723,16 +1826,16 @@
 }
 
 // For given CB object, fetch associated CB Node from map
-GLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
-    auto it = dev_data->commandBufferMap.find(cb);
-    if (it == dev_data->commandBufferMap.end()) {
+GLOBAL_CB_NODE *CoreChecks::GetCBNode(const VkCommandBuffer cb) {
+    auto it = commandBufferMap.find(cb);
+    if (it == commandBufferMap.end()) {
         return NULL;
     }
     return it->second;
 }
 
 // If a renderpass is active, verify that the given command type is appropriate for current subpass state
-bool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
+bool CoreChecks::ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
     if (!pCB->activeRenderPass) return false;
     bool skip = false;
     if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
@@ -1749,11 +1852,11 @@
     return skip;
 }
 
-bool ValidateCmdQueueFlags(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *caller_name,
-                           VkQueueFlags required_flags, const std::string &error_code) {
-    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
+bool CoreChecks::ValidateCmdQueueFlags(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *caller_name,
+                                       VkQueueFlags required_flags, const char *error_code) {
+    auto pool = GetCommandPoolNode(cb_node->createInfo.commandPool);
     if (pool) {
-        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
+        VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pool->queueFamilyIndex].queueFlags;
         if (!(required_flags & queue_flags)) {
             string required_flags_string;
             for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
@@ -1779,15 +1882,16 @@
     return "destroyed";
 }
 
-static bool ReportInvalidCommandBuffer(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state, const char *call_source) {
+bool CoreChecks::ReportInvalidCommandBuffer(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state, const char *call_source) {
     bool skip = false;
     for (auto obj : cb_state->broken_bindings) {
         const char *type_str = object_string[obj.type];
         const char *cause_str = GetCauseStr(obj);
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_state->commandBuffer), kVUID_Core_DrawState_InvalidCommandBuffer,
-                        "You are adding %s to command buffer 0x%" PRIx64 " that is invalid because bound %s 0x%" PRIx64 " was %s.",
-                        call_source, HandleToUint64(cb_state->commandBuffer), type_str, obj.handle, cause_str);
+                        "You are adding %s to command buffer %s that is invalid because bound %s %s was %s.", call_source,
+                        dev_data->report_data->FormatHandle(cb_state->commandBuffer).c_str(), type_str,
+                        dev_data->report_data->FormatHandle(obj.handle).c_str(), cause_str);
     }
     return skip;
 }
@@ -1877,7 +1981,7 @@
 
 // Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
 // there's an issue with the Cmd ordering
-bool ValidateCmd(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
+bool CoreChecks::ValidateCmd(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
     switch (cb_state->state) {
         case CB_RECORDING:
             return ValidateCmdSubpassState(dev_data, cb_state, cmd);
@@ -1901,63 +2005,63 @@
 }
 
 // For given object struct return a ptr of BASE_NODE type for its wrapping struct
-BASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
+BASE_NODE *CoreChecks::GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
     BASE_NODE *base_ptr = nullptr;
     switch (object_struct.type) {
         case kVulkanObjectTypeDescriptorSet: {
-            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
+            base_ptr = GetSetNode(reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeSampler: {
-            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
+            base_ptr = GetSamplerState(reinterpret_cast<VkSampler &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeQueryPool: {
-            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
+            base_ptr = GetQueryPoolNode(reinterpret_cast<VkQueryPool &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypePipeline: {
-            base_ptr = GetPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
+            base_ptr = GetPipelineState(reinterpret_cast<VkPipeline &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeBuffer: {
-            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
+            base_ptr = GetBufferState(reinterpret_cast<VkBuffer &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeBufferView: {
-            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
+            base_ptr = GetBufferViewState(reinterpret_cast<VkBufferView &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeImage: {
-            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
+            base_ptr = GetImageState(reinterpret_cast<VkImage &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeImageView: {
-            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
+            base_ptr = GetImageViewState(reinterpret_cast<VkImageView &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeEvent: {
-            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
+            base_ptr = GetEventNode(reinterpret_cast<VkEvent &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeDescriptorPool: {
-            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
+            base_ptr = GetDescriptorPoolState(reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeCommandPool: {
-            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
+            base_ptr = GetCommandPoolNode(reinterpret_cast<VkCommandPool &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeFramebuffer: {
-            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
+            base_ptr = GetFramebufferState(reinterpret_cast<VkFramebuffer &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeRenderPass: {
-            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
+            base_ptr = GetRenderPassState(reinterpret_cast<VkRenderPass &>(object_struct.handle));
             break;
         }
         case kVulkanObjectTypeDeviceMemory: {
-            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
+            base_ptr = GetMemObjInfo(reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
             break;
         }
         default:
@@ -1976,13 +2080,13 @@
     cb_node->object_bindings.insert(obj);
 }
 // For a given object, if cb_node is in that objects cb_bindings, remove cb_node
-static void RemoveCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
+void CoreChecks::RemoveCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
     BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
     if (base_obj) base_obj->cb_bindings.erase(cb_node);
 }
 // Reset the command buffer state
 //  Maintain the createInfo and set state to CB_NEW, but clear all other state
-static void ResetCommandBufferState(layer_data *dev_data, const VkCommandBuffer cb) {
+void CoreChecks::ResetCommandBufferState(layer_data *dev_data, const VkCommandBuffer cb) {
     GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
     if (pCB) {
         pCB->in_use.store(0);
@@ -2046,7 +2150,7 @@
         pCB->object_bindings.clear();
         // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
         for (auto framebuffer : pCB->framebuffers) {
-            auto fb_state = GetFramebufferState(dev_data, framebuffer);
+            auto fb_state = GetFramebufferState(framebuffer);
             if (fb_state) fb_state->cb_bindings.erase(pCB);
         }
         pCB->framebuffers.clear();
@@ -2109,20 +2213,20 @@
 
 // Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
 // render pass.
-bool InsideRenderPass(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const char *apiName, const std::string &msgCode) {
+bool CoreChecks::InsideRenderPass(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const char *apiName, const char *msgCode) {
     bool inside = false;
     if (pCB->activeRenderPass) {
         inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                          HandleToUint64(pCB->commandBuffer), msgCode,
-                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIx64 ").", apiName,
-                         HandleToUint64(pCB->activeRenderPass->renderPass));
+                         "%s: It is invalid to issue this call inside an active render pass (%s).", apiName,
+                         dev_data->report_data->FormatHandle(pCB->activeRenderPass->renderPass).c_str());
     }
     return inside;
 }
 
 // Flags validation error if the associated call is made outside a render pass. The apiName
 // routine should ONLY be called inside a render pass.
-bool OutsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, const std::string &msgCode) {
+bool CoreChecks::OutsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, const char *msgCode) {
     bool outside = false;
     if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
         ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
@@ -2134,111 +2238,40 @@
     return outside;
 }
 
-static void InitCoreValidation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
-    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
-                                  "lunarg_core_validation");
-}
-
-// For the given ValidationCheck enum, set all relevant instance disabled flags to true
-void SetDisabledFlags(instance_layer_data *instance_data, const VkValidationFlagsEXT *val_flags_struct) {
-    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
-        switch (val_flags_struct->pDisabledValidationChecks[i]) {
-            case VK_VALIDATION_CHECK_SHADERS_EXT:
-                instance_data->disabled.shader_validation = true;
-                break;
-            case VK_VALIDATION_CHECK_ALL_EXT:
-                // Set all disabled flags to true
-                instance_data->disabled.SetAll(true);
-                break;
-            default:
-                break;
-        }
+void CoreChecks::InitGpuValidation(instance_layer_data *instance_data) {
+    // Process the layer settings file.
+    enum CoreValidationGpuFlagBits {
+        CORE_VALIDATION_GPU_VALIDATION_ALL_BIT = 0x00000001,
+        CORE_VALIDATION_GPU_VALIDATION_RESERVE_BINDING_SLOT_BIT = 0x00000002,
+    };
+    typedef VkFlags CoreGPUFlags;
+    static const std::unordered_map<std::string, VkFlags> gpu_flags_option_definitions = {
+        {std::string("all"), CORE_VALIDATION_GPU_VALIDATION_ALL_BIT},
+        {std::string("reserve_binding_slot"), CORE_VALIDATION_GPU_VALIDATION_RESERVE_BINDING_SLOT_BIT},
+    };
+    std::string gpu_flags_key = "lunarg_core_validation.gpu_validation";
+    CoreGPUFlags gpu_flags = GetLayerOptionFlags(gpu_flags_key, gpu_flags_option_definitions, 0);
+    if (gpu_flags & CORE_VALIDATION_GPU_VALIDATION_ALL_BIT) {
+        instance_data->instance_state->enabled.gpu_validation = true;
+    }
+    if (gpu_flags & CORE_VALIDATION_GPU_VALIDATION_RESERVE_BINDING_SLOT_BIT) {
+        instance_data->instance_state->enabled.gpu_validation_reserve_binding_slot = true;
     }
 }
 
-static void PreCallRecordCreateInstance(VkLayerInstanceCreateInfo *chain_info) {
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-}
-
-static void PostCallValidateCreateInstance(const VkInstanceCreateInfo *pCreateInfo) { ValidateLayerOrdering(*pCreateInfo); }
-
-static void PostCallRecordCreateInstance(instance_layer_data *instance_data, const VkInstanceCreateInfo *pCreateInfo) {
-    // Parse any pNext chains
-    const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(pCreateInfo->pNext);
-    if (validation_flags_ext) {
-        SetDisabledFlags(instance_data, validation_flags_ext);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                                              VkInstance *pInstance) {
-    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
-    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
-
-    PreCallRecordCreateInstance(chain_info);
-
-    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
-    if (result != VK_SUCCESS) return result;
-
+void CoreChecks::PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
+                                              VkInstance *pInstance, VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
-    instance_data->instance = *pInstance;
-    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
-    instance_data->report_data = debug_utils_create_instance(
-        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
-
-    instance_data->api_version = instance_data->extensions.InitFromInstanceCreateInfo(
-        (pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0), pCreateInfo);
-    InitCoreValidation(instance_data, pAllocator);
-
-    PostCallValidateCreateInstance(pCreateInfo);
-    PostCallRecordCreateInstance(instance_data, pCreateInfo);
-
-    return result;
-}
-
-static void PostCallRecordDestroyInstance(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator,
-                                          dispatch_key key) {
-    // Clean up logging callback, if any
-    while (instance_data->logging_messenger.size() > 0) {
-        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
-        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-        instance_data->logging_messenger.pop_back();
-    }
-    while (instance_data->logging_callback.size() > 0) {
-        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
-        instance_data->logging_callback.pop_back();
-    }
-
-    layer_debug_utils_destroy_instance(instance_data->report_data);
-    FreeLayerDataPtr(key, instance_layer_data_map);
-}
-
-// Hook DestroyInstance to remove tableInstanceMap entry
-VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    // TODOSC : Shouldn't need any customization here
-    dispatch_key key = get_dispatch_key(instance);
-    // TBD: Need any locking this early, in case this function is called at the
-    // same time by more than one thread?
-    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
-    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
-
-    lock_guard_t lock(global_lock);
-    PostCallRecordDestroyInstance(instance_data, pAllocator, key);
+    if (VK_SUCCESS != result) return;
+    InitGpuValidation(instance_data);
 }
 
 static bool ValidatePhysicalDeviceQueueFamily(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
-                                              uint32_t requested_queue_family, std::string err_code, const char *cmd_name,
+                                              uint32_t requested_queue_family, const char *err_code, const char *cmd_name,
                                               const char *queue_family_var_name) {
     bool skip = false;
 
-    const char *conditional_ext_cmd = instance_data->extensions.vk_khr_get_physical_device_properties_2
+    const char *conditional_ext_cmd = instance_data->instance_extensions.vk_khr_get_physical_device_properties_2
                                           ? " or vkGetPhysicalDeviceQueueFamilyProperties2[KHR]"
                                           : "";
 
@@ -2262,6 +2295,8 @@
                                            uint32_t info_count, const VkDeviceQueueCreateInfo *infos) {
     bool skip = false;
 
+    std::unordered_set<uint32_t> queue_family_set;
+
     for (uint32_t i = 0; i < info_count; ++i) {
         const auto requested_queue_family = infos[i].queueFamilyIndex;
 
@@ -2270,13 +2305,21 @@
         skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, requested_queue_family,
                                                   "VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381", "vkCreateDevice",
                                                   queue_family_var_name.c_str());
+        if (queue_family_set.count(requested_queue_family)) {
+            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(pd_state->phys_device), "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372",
+                            "CreateDevice(): %s (=%" PRIu32 ") is not unique within pQueueCreateInfos.",
+                            queue_family_var_name.c_str(), requested_queue_family);
+        } else {
+            queue_family_set.insert(requested_queue_family);
+        }
 
         // Verify that requested  queue count of queue family is known to be valid at this point in time
         if (requested_queue_family < pd_state->queue_family_count) {
             const auto requested_queue_count = infos[i].queueCount;
             const auto queue_family_props_count = pd_state->queue_family_properties.size();
             const bool queue_family_has_props = requested_queue_family < queue_family_props_count;
-            const char *conditional_ext_cmd = instance_data->extensions.vk_khr_get_physical_device_properties_2
+            const char *conditional_ext_cmd = instance_data->instance_extensions.vk_khr_get_physical_device_properties_2
                                                   ? " or vkGetPhysicalDeviceQueueFamilyProperties2[KHR]"
                                                   : "";
             std::string count_note =
@@ -2301,233 +2344,230 @@
     return skip;
 }
 
-static bool PreCallValidateCreateDevice(instance_layer_data *instance_data, const VkPhysicalDeviceFeatures **enabled_features_found,
-                                        VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
+                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
     bool skip = false;
-    auto pd_state = GetPhysicalDeviceState(instance_data, gpu);
+    auto pd_state = GetPhysicalDeviceState(gpu);
 
     // TODO: object_tracker should perhaps do this instead
     //       and it does not seem to currently work anyway -- the loader just crashes before this point
-    if (!GetPhysicalDeviceState(instance_data, gpu)) {
+    if (!pd_state) {
         skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                         0, kVUID_Core_DevLimit_MustQueryCount,
                         "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
     }
-
-    // The enabled features can come from either pEnabledFeatures, or from the pNext chain
-    // TODO: Validate "VUID-VkDeviceCreateInfo-pNext-00373" here, can't have non-null pEnabledFeatures & GPDF2 in pNext chain
-    if (nullptr == *enabled_features_found) {
-        const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
-        if (features2) {
-            *enabled_features_found = &(features2->features);
-        }
-    }
-
     skip |=
         ValidateDeviceQueueCreateInfos(instance_data, pd_state, pCreateInfo->queueCreateInfoCount, pCreateInfo->pQueueCreateInfos);
-
     return skip;
 }
 
-static void PreCallRecordCreateDevice(VkLayerDeviceCreateInfo *chain_info) {
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+void CoreChecks::PreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator, VkDevice *pDevice,
+                                           std::unique_ptr<safe_VkDeviceCreateInfo> &modified_create_info) {
+    // GPU Validation can possibly turn on device features, so give it a chance to change the create info.
+    if (GetEnables()->gpu_validation) {
+        VkPhysicalDeviceFeatures supported_features;
+        instance_dispatch_table.GetPhysicalDeviceFeatures(gpu, &supported_features);
+        GpuPreCallRecordCreateDevice(gpu, modified_create_info, &supported_features);
+    }
 }
 
-static void PostCallValidateCreateDevice(const VkDeviceCreateInfo *pCreateInfo) { ValidateLayerOrdering(*pCreateInfo); }
+void CoreChecks::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
+    if (VK_SUCCESS != result) return;
 
-static void PostCallRecordCreateDevice(instance_layer_data *instance_data, const VkPhysicalDeviceFeatures *enabled_features_found,
-                                       PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr, VkPhysicalDevice gpu,
-                                       const VkDeviceCreateInfo *pCreateInfo, VkDevice *pDevice) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-
-    device_data->instance_data = instance_data;
-    // Setup device dispatch table
-    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
-    device_data->device = *pDevice;
-    // Save PhysicalDevice handle
-    device_data->physical_device = gpu;
-
-    device_data->report_data = layer_debug_utils_create_device(instance_data->report_data, *pDevice);
-
-    // Get physical device limits for this device
-    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
-
-    // Setup the validation tables based on the application API version from the instance and the capabilities of the device driver.
-    uint32_t effective_api_version = std::min(device_data->phys_dev_properties.properties.apiVersion, instance_data->api_version);
-    device_data->api_version =
-        device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, effective_api_version, pCreateInfo);
-
-    uint32_t count;
-    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
-    device_data->phys_dev_properties.queue_family_properties.resize(count);
-    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
-        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
-    // TODO: device limits should make sure these are compatible
-    if (enabled_features_found) {
-        device_data->enabled_features.core = *enabled_features_found;
+    const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
+    if (nullptr == enabled_features_found) {
+        const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
+        if (features2) {
+            enabled_features_found = &(features2->features);
+        }
     }
 
+    ValidationObject *device_object = ::GetLayerDataPtr(::get_dispatch_key(*pDevice), ::layer_data_map);
+    ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeCoreValidation);
+    CoreChecks *core_checks = static_cast<CoreChecks *>(validation_data);
+
+    if (nullptr == enabled_features_found) {
+        core_checks->enabled_features.core = {};
+    } else {
+        core_checks->enabled_features.core = *enabled_features_found;
+    }
+
+    // Make sure that queue_family_properties are obtained for this device's physical_device, even if the app has not
+    // previously set them through an explicit API call.
+    uint32_t count;
+    auto pd_state = GetPhysicalDeviceState(gpu);
+    instance_dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
+    pd_state->queue_family_count = std::max(pd_state->queue_family_count, count);
+    pd_state->queue_family_properties.resize(std::max(static_cast<uint32_t>(pd_state->queue_family_properties.size()), count));
+    instance_dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, &pd_state->queue_family_properties[0]);
+    // Save local link to this device's physical device state
+    core_checks->physical_device_state = pd_state;
+
+    const auto *device_group_ci = lvl_find_in_chain<VkDeviceGroupDeviceCreateInfo>(pCreateInfo->pNext);
+    core_checks->physical_device_count =
+        device_group_ci && device_group_ci->physicalDeviceCount > 0 ? device_group_ci->physicalDeviceCount : 1;
+
     const auto *descriptor_indexing_features = lvl_find_in_chain<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(pCreateInfo->pNext);
     if (descriptor_indexing_features) {
-        device_data->enabled_features.descriptor_indexing = *descriptor_indexing_features;
+        core_checks->enabled_features.descriptor_indexing = *descriptor_indexing_features;
     }
 
     const auto *eight_bit_storage_features = lvl_find_in_chain<VkPhysicalDevice8BitStorageFeaturesKHR>(pCreateInfo->pNext);
     if (eight_bit_storage_features) {
-        device_data->enabled_features.eight_bit_storage = *eight_bit_storage_features;
+        core_checks->enabled_features.eight_bit_storage = *eight_bit_storage_features;
     }
 
     const auto *exclusive_scissor_features = lvl_find_in_chain<VkPhysicalDeviceExclusiveScissorFeaturesNV>(pCreateInfo->pNext);
     if (exclusive_scissor_features) {
-        device_data->enabled_features.exclusive_scissor = *exclusive_scissor_features;
+        core_checks->enabled_features.exclusive_scissor = *exclusive_scissor_features;
     }
 
     const auto *shading_rate_image_features = lvl_find_in_chain<VkPhysicalDeviceShadingRateImageFeaturesNV>(pCreateInfo->pNext);
     if (shading_rate_image_features) {
-        device_data->enabled_features.shading_rate_image = *shading_rate_image_features;
+        core_checks->enabled_features.shading_rate_image = *shading_rate_image_features;
     }
 
     const auto *mesh_shader_features = lvl_find_in_chain<VkPhysicalDeviceMeshShaderFeaturesNV>(pCreateInfo->pNext);
     if (mesh_shader_features) {
-        device_data->enabled_features.mesh_shader = *mesh_shader_features;
+        core_checks->enabled_features.mesh_shader = *mesh_shader_features;
     }
 
     const auto *inline_uniform_block_features =
         lvl_find_in_chain<VkPhysicalDeviceInlineUniformBlockFeaturesEXT>(pCreateInfo->pNext);
     if (inline_uniform_block_features) {
-        device_data->enabled_features.inline_uniform_block = *inline_uniform_block_features;
+        core_checks->enabled_features.inline_uniform_block = *inline_uniform_block_features;
+    }
+
+    const auto *transform_feedback_features = lvl_find_in_chain<VkPhysicalDeviceTransformFeedbackFeaturesEXT>(pCreateInfo->pNext);
+    if (transform_feedback_features) {
+        core_checks->enabled_features.transform_feedback_features = *transform_feedback_features;
+    }
+
+    const auto *float16_int8_features = lvl_find_in_chain<VkPhysicalDeviceFloat16Int8FeaturesKHR>(pCreateInfo->pNext);
+    if (float16_int8_features) {
+        core_checks->enabled_features.float16_int8 = *float16_int8_features;
+    }
+
+    const auto *vtx_attrib_div_features = lvl_find_in_chain<VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT>(pCreateInfo->pNext);
+    if (vtx_attrib_div_features) {
+        core_checks->enabled_features.vtx_attrib_divisor_features = *vtx_attrib_div_features;
+    }
+
+    const auto *scalar_block_layout_features = lvl_find_in_chain<VkPhysicalDeviceScalarBlockLayoutFeaturesEXT>(pCreateInfo->pNext);
+    if (scalar_block_layout_features) {
+        core_checks->enabled_features.scalar_block_layout_features = *scalar_block_layout_features;
+    }
+
+    const auto *buffer_address = lvl_find_in_chain<VkPhysicalDeviceBufferAddressFeaturesEXT>(pCreateInfo->pNext);
+    if (buffer_address) {
+        core_checks->enabled_features.buffer_address = *buffer_address;
     }
 
     // Store physical device properties and physical device mem limits into device layer_data structs
-    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
-    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
+    instance_dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &core_checks->phys_dev_mem_props);
+    instance_dispatch_table.GetPhysicalDeviceProperties(gpu, &core_checks->phys_dev_props);
 
-    if (device_data->extensions.vk_khr_push_descriptor) {
+    if (core_checks->device_extensions.vk_khr_push_descriptor) {
         // Get the needed push_descriptor limits
         auto push_descriptor_prop = lvl_init_struct<VkPhysicalDevicePushDescriptorPropertiesKHR>();
         auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&push_descriptor_prop);
-        instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
-        device_data->phys_dev_ext_props.max_push_descriptors = push_descriptor_prop.maxPushDescriptors;
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.max_push_descriptors = push_descriptor_prop.maxPushDescriptors;
     }
-    if (device_data->extensions.vk_ext_descriptor_indexing) {
+    if (core_checks->device_extensions.vk_ext_descriptor_indexing) {
         // Get the needed descriptor_indexing limits
         auto descriptor_indexing_props = lvl_init_struct<VkPhysicalDeviceDescriptorIndexingPropertiesEXT>();
         auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&descriptor_indexing_props);
-        instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
-        device_data->phys_dev_ext_props.descriptor_indexing_props = descriptor_indexing_props;
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.descriptor_indexing_props = descriptor_indexing_props;
     }
-    if (device_data->extensions.vk_nv_shading_rate_image) {
+    if (core_checks->device_extensions.vk_nv_shading_rate_image) {
         // Get the needed shading rate image limits
         auto shading_rate_image_props = lvl_init_struct<VkPhysicalDeviceShadingRateImagePropertiesNV>();
         auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&shading_rate_image_props);
-        instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
-        device_data->phys_dev_ext_props.shading_rate_image_props = shading_rate_image_props;
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.shading_rate_image_props = shading_rate_image_props;
     }
-    if (device_data->extensions.vk_nv_mesh_shader) {
+    if (core_checks->device_extensions.vk_nv_mesh_shader) {
         // Get the needed mesh shader limits
         auto mesh_shader_props = lvl_init_struct<VkPhysicalDeviceMeshShaderPropertiesNV>();
         auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&mesh_shader_props);
-        instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
-        device_data->phys_dev_ext_props.mesh_shader_props = mesh_shader_props;
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.mesh_shader_props = mesh_shader_props;
     }
-    if (device_data->extensions.vk_ext_inline_uniform_block) {
+    if (core_checks->device_extensions.vk_ext_inline_uniform_block) {
         // Get the needed inline uniform block limits
         auto inline_uniform_block_props = lvl_init_struct<VkPhysicalDeviceInlineUniformBlockPropertiesEXT>();
         auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&inline_uniform_block_props);
-        instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
-        device_data->phys_dev_ext_props.inline_uniform_block_props = inline_uniform_block_props;
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.inline_uniform_block_props = inline_uniform_block_props;
+    }
+    if (core_checks->device_extensions.vk_ext_vertex_attribute_divisor) {
+        // Get the needed vertex attribute divisor limits
+        auto vtx_attrib_divisor_props = lvl_init_struct<VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT>();
+        auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&vtx_attrib_divisor_props);
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.vtx_attrib_divisor_props = vtx_attrib_divisor_props;
+    }
+    if (core_checks->device_extensions.vk_khr_depth_stencil_resolve) {
+        // Get the needed depth and stencil resolve modes
+        auto depth_stencil_resolve_props = lvl_init_struct<VkPhysicalDeviceDepthStencilResolvePropertiesKHR>();
+        auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&depth_stencil_resolve_props);
+        instance_dispatch_table.GetPhysicalDeviceProperties2KHR(gpu, &prop2);
+        core_checks->phys_dev_ext_props.depth_stencil_resolve_props = depth_stencil_resolve_props;
+    }
+    if (GetEnables()->gpu_validation) {
+        // Copy any needed instance data into the gpu validation state
+        core_checks->gpu_validation_state.reserve_binding_slot = GetEnables()->gpu_validation_reserve_binding_slot;
+        core_checks->GpuPostCallRecordCreateDevice(core_checks);
+    }
+
+    // Store queue family data
+    if ((pCreateInfo != nullptr) && (pCreateInfo->pQueueCreateInfos != nullptr)) {
+        for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) {
+            core_checks->queue_family_index_map.insert(
+                std::make_pair(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, pCreateInfo->pQueueCreateInfos[i].queueCount));
+        }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
-                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
-
-    bool skip = PreCallValidateCreateDevice(instance_data, &enabled_features_found, gpu, pCreateInfo);
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
-    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
-    if (fpCreateDevice == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
+void CoreChecks::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    if (!device) return;
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallRecordDestroyDevice(device_data);
     }
-
-    // Advance the link info for the next element on the chain
-    PreCallRecordCreateDevice(chain_info);
-    lock.unlock();
-
-    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    lock.lock();
-    PostCallRecordCreateDevice(instance_data, enabled_features_found, fpGetDeviceProcAddr, gpu, pCreateInfo, pDevice);
-    PostCallValidateCreateDevice(pCreateInfo);
-    lock.unlock();
-
-    return result;
-}
-
-static void PreCallRecordDestroyDevice(layer_data *dev_data, VkDevice device) {
-    dev_data->pipelineMap.clear();
-    dev_data->renderPassMap.clear();
-    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
+    device_data->pipelineMap.clear();
+    device_data->renderPassMap.clear();
+    for (auto ii = device_data->commandBufferMap.begin(); ii != device_data->commandBufferMap.end(); ++ii) {
         delete (*ii).second;
     }
-    dev_data->commandBufferMap.clear();
+    device_data->commandBufferMap.clear();
     // This will also delete all sets in the pool & remove them from setMap
-    DeletePools(dev_data);
+    DeletePools(device_data);
     // All sets should be removed
-    assert(dev_data->setMap.empty());
-    dev_data->descriptorSetLayoutMap.clear();
-    dev_data->imageViewMap.clear();
-    dev_data->imageMap.clear();
-    dev_data->imageSubresourceMap.clear();
-    dev_data->imageLayoutMap.clear();
-    dev_data->bufferViewMap.clear();
-    dev_data->bufferMap.clear();
+    assert(device_data->setMap.empty());
+    device_data->descriptorSetLayoutMap.clear();
+    device_data->imageViewMap.clear();
+    device_data->imageMap.clear();
+    device_data->imageSubresourceMap.clear();
+    device_data->imageLayoutMap.clear();
+    device_data->bufferViewMap.clear();
+    device_data->bufferMap.clear();
     // Queues persist until device is destroyed
-    dev_data->queueMap.clear();
-    // Report any memory leaks
+    device_data->queueMap.clear();
     layer_debug_utils_destroy_device(device);
 }
 
-static void PostCallRecordDestroyDevice(const dispatch_key &key) { FreeLayerDataPtr(key, layer_data_map); }
-
-VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    // TODOSC : Shouldn't need any customization here
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
-    unique_lock_t lock(global_lock);
-    PreCallRecordDestroyDevice(dev_data, device);
-    lock.unlock();
-
-#if DISPATCH_MAP_DEBUG
-    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
-#endif
-
-    dev_data->dispatch_table.DestroyDevice(device, pAllocator);
-
-    // Free all the memory
-    lock.lock();
-    PostCallRecordDestroyDevice(key);
-}
-
-static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
-
 // For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
 //   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id.
 // Similarly for mesh and task shaders.
 static bool ValidateStageMaskGsTsEnables(const layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
-                                         std::string geo_error_id, std::string tess_error_id, std::string mesh_error_id,
-                                         std::string task_error_id) {
+                                         const char *geo_error_id, const char *tess_error_id, const char *mesh_error_id,
+                                         const char *task_error_id) {
     bool skip = false;
     if (!dev_data->enabled_features.core.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
         skip |=
@@ -2563,7 +2603,7 @@
 }
 
 // Loop through bound objects and increment their in_use counts.
-static void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
+void CoreChecks::IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
     for (auto obj : cb_node->object_bindings) {
         auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
         if (base_obj) {
@@ -2572,7 +2612,7 @@
     }
 }
 // Track which resources are in-flight by atomically incrementing their "in_use" count
-static void IncrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+void CoreChecks::IncrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     cb_node->submitCount++;
     cb_node->in_use.fetch_add(1);
 
@@ -2583,14 +2623,14 @@
     //  should then be flagged prior to calling this function
     for (auto draw_data_element : cb_node->draw_data) {
         for (auto &vertex_buffer : draw_data_element.vertex_buffer_bindings) {
-            auto buffer_state = GetBufferState(dev_data, vertex_buffer.buffer);
+            auto buffer_state = GetBufferState(vertex_buffer.buffer);
             if (buffer_state) {
                 buffer_state->in_use.fetch_add(1);
             }
         }
     }
     for (auto event : cb_node->writeEventsBeforeWait) {
-        auto event_state = GetEventNode(dev_data, event);
+        auto event_state = GetEventNode(event);
         if (event_state) event_state->write_in_use++;
     }
 }
@@ -2599,7 +2639,7 @@
 // For the given queue, verify the queue state up to the given seq number.
 // Currently the only check is to make sure that if there are events to be waited on prior to
 //  a QueryReset, make sure that all such events have been signalled.
-static bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
+bool CoreChecks::VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
     bool skip = false;
 
     // sequence number we want to validate up to, per queue
@@ -2618,7 +2658,7 @@
 
         for (; seq < target_seq; ++sub_it, ++seq) {
             for (auto &wait : sub_it->waitSemaphores) {
-                auto other_queue = GetQueueState(dev_data, wait.queue);
+                auto other_queue = GetQueueState(wait.queue);
 
                 if (other_queue == queue) continue;  // semaphores /always/ point backwards, so no point here.
 
@@ -2643,16 +2683,16 @@
 }
 
 // When the given fence is retired, verify outstanding queue operations through the point of the fence
-static bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
-    auto fence_state = GetFenceNode(dev_data, fence);
+bool CoreChecks::VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
+    auto fence_state = GetFenceNode(fence);
     if (fence_state && fence_state->scope == kSyncScopeInternal && VK_NULL_HANDLE != fence_state->signaler.first) {
-        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
+        return VerifyQueueStateToSeq(dev_data, GetQueueState(fence_state->signaler.first), fence_state->signaler.second);
     }
     return false;
 }
 
 // Decrement in-use count for objects bound to command buffer
-static void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
+void CoreChecks::DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
     BASE_NODE *base_obj = nullptr;
     for (auto obj : cb_node->object_bindings) {
         base_obj = GetStateStructPtrFromObject(dev_data, obj);
@@ -2662,7 +2702,7 @@
     }
 }
 
-static void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
+void CoreChecks::RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
     std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
 
     // Roll this queue forward, one submission at a time.
@@ -2670,7 +2710,7 @@
         auto &submission = pQueue->submissions.front();
 
         for (auto &wait : submission.waitSemaphores) {
-            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
+            auto pSemaphore = GetSemaphoreNode(wait.semaphore);
             if (pSemaphore) {
                 pSemaphore->in_use.fetch_sub(1);
             }
@@ -2679,21 +2719,21 @@
         }
 
         for (auto &semaphore : submission.signalSemaphores) {
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 pSemaphore->in_use.fetch_sub(1);
             }
         }
 
         for (auto &semaphore : submission.externalSemaphores) {
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 pSemaphore->in_use.fetch_sub(1);
             }
         }
 
         for (auto cb : submission.cbs) {
-            auto cb_node = GetCBNode(dev_data, cb);
+            auto cb_node = GetCBNode(cb);
             if (!cb_node) {
                 continue;
             }
@@ -2701,7 +2741,7 @@
             DecrementBoundResources(dev_data, cb_node);
             for (auto draw_data_element : cb_node->draw_data) {
                 for (auto &vertex_buffer_binding : draw_data_element.vertex_buffer_bindings) {
-                    auto buffer_state = GetBufferState(dev_data, vertex_buffer_binding.buffer);
+                    auto buffer_state = GetBufferState(vertex_buffer_binding.buffer);
                     if (buffer_state) {
                         buffer_state->in_use.fetch_sub(1);
                     }
@@ -2723,7 +2763,7 @@
             cb_node->in_use.fetch_sub(1);
         }
 
-        auto pFence = GetFenceNode(dev_data, submission.fence);
+        auto pFence = GetFenceNode(submission.fence);
         if (pFence && pFence->scope == kSyncScopeInternal) {
             pFence->state = FENCE_RETIRED;
         }
@@ -2734,7 +2774,7 @@
 
     // Roll other queues forward to the highest seq we saw a wait for
     for (auto qs : otherQueueSeqs) {
-        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
+        RetireWorkOnQueue(dev_data, GetQueueState(qs.first), qs.second);
     }
 }
 
@@ -2746,31 +2786,31 @@
     pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
 }
 
-static bool ValidateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
+bool CoreChecks::ValidateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
     bool skip = false;
     if ((pCB->in_use.load() || current_submit_count > 1) &&
         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
                         "VUID-vkQueueSubmit-pCommandBuffers-00071",
-                        "Command Buffer 0x%" PRIx64 " is already in use and is not marked for simultaneous use.",
-                        HandleToUint64(pCB->commandBuffer));
+                        "Command Buffer %s is already in use and is not marked for simultaneous use.",
+                        dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str());
     }
     return skip;
 }
 
-static bool ValidateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
-                                       int current_submit_count, std::string vu_id) {
+bool CoreChecks::ValidateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
+                                            int current_submit_count, const char *vu_id) {
     bool skip = false;
     if (dev_data->instance_data->disabled.command_buffer_state) return skip;
     // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
     if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
         (cb_state->submitCount + current_submit_count > 1)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
-                        kVUID_Core_DrawState_CommandBufferSingleSubmitViolation,
-                        "Commandbuffer 0x%" PRIx64
-                        " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set, but has been submitted 0x%" PRIxLEAST64
-                        " times.",
-                        HandleToUint64(cb_state->commandBuffer), cb_state->submitCount + current_submit_count);
+        skip |= log_msg(
+            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
+            kVUID_Core_DrawState_CommandBufferSingleSubmitViolation,
+            "Commandbuffer %s was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set, but has been submitted 0x%" PRIxLEAST64
+            "times.",
+            dev_data->report_data->FormatHandle(cb_state->commandBuffer).c_str(), cb_state->submitCount + current_submit_count);
     }
 
     // Validate that cmd buffers have been updated
@@ -2783,15 +2823,15 @@
         case CB_NEW:
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             (uint64_t)(cb_state->commandBuffer), vu_id,
-                            "Command buffer 0x%" PRIx64 " used in the call to %s is unrecorded and contains no commands.",
-                            HandleToUint64(cb_state->commandBuffer), call_source);
+                            "Command buffer %s used in the call to %s is unrecorded and contains no commands.",
+                            dev_data->report_data->FormatHandle(cb_state->commandBuffer).c_str(), call_source);
             break;
 
         case CB_RECORDING:
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), kVUID_Core_DrawState_NoEndCommandBuffer,
-                            "You must call vkEndCommandBuffer() on command buffer 0x%" PRIx64 " before this call to %s!",
-                            HandleToUint64(cb_state->commandBuffer), call_source);
+                            "You must call vkEndCommandBuffer() on command buffer %s before this call to %s!",
+                            dev_data->report_data->FormatHandle(cb_state->commandBuffer).c_str(), call_source);
             break;
 
         default: /* recorded */
@@ -2800,7 +2840,7 @@
     return skip;
 }
 
-static bool ValidateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+bool CoreChecks::ValidateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     bool skip = false;
 
     // TODO : We should be able to remove the NULL look-up checks from the code below as long as
@@ -2808,12 +2848,12 @@
     //  should then be flagged prior to calling this function
     for (const auto &draw_data_element : cb_node->draw_data) {
         for (const auto &vertex_buffer_binding : draw_data_element.vertex_buffer_bindings) {
-            auto buffer_state = GetBufferState(dev_data, vertex_buffer_binding.buffer);
+            auto buffer_state = GetBufferState(vertex_buffer_binding.buffer);
             if ((vertex_buffer_binding.buffer != VK_NULL_HANDLE) && (!buffer_state)) {
                 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                                 HandleToUint64(vertex_buffer_binding.buffer), kVUID_Core_DrawState_InvalidBuffer,
-                                "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".",
-                                HandleToUint64(vertex_buffer_binding.buffer));
+                                "Cannot submit cmd buffer using deleted buffer %s.",
+                                dev_data->report_data->FormatHandle(vertex_buffer_binding.buffer).c_str());
             }
         }
     }
@@ -2821,11 +2861,11 @@
 }
 
 // Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
-bool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
-                           const uint32_t *indices) {
+bool CoreChecks::ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue,
+                                       uint32_t count, const uint32_t *indices) {
     bool found = false;
     bool skip = false;
-    auto queue_state = GetQueueState(dev_data, queue);
+    auto queue_state = GetQueueState(queue);
     if (queue_state) {
         for (uint32_t i = 0; i < count; i++) {
             if (indices[i] == queue_state->queueFamilyIndex) {
@@ -2837,10 +2877,10 @@
         if (!found) {
             skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object->type],
                            object->handle, kVUID_Core_DrawState_InvalidQueueFamily,
-                           "vkQueueSubmit: Command buffer 0x%" PRIx64 " contains %s 0x%" PRIx64
-                           " which was not created allowing concurrent access to this queue family %d.",
-                           HandleToUint64(cb_node->commandBuffer), object_string[object->type], object->handle,
-                           queue_state->queueFamilyIndex);
+                           "vkQueueSubmit: Command buffer %s contains %s %s which was not created allowing concurrent access to "
+                           "this queue family %d.",
+                           dev_data->report_data->FormatHandle(cb_node->commandBuffer).c_str(), object_string[object->type],
+                           dev_data->report_data->FormatHandle(object->handle).c_str(), queue_state->queueFamilyIndex);
         }
     }
     return skip;
@@ -2848,31 +2888,31 @@
 
 // Validate that queueFamilyIndices of primary command buffers match this queue
 // Secondary command buffers were previously validated in vkCmdExecuteCommands().
-static bool ValidateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
+bool CoreChecks::ValidateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
     bool skip = false;
-    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
-    auto queue_state = GetQueueState(dev_data, queue);
+    auto pPool = GetCommandPoolNode(pCB->createInfo.commandPool);
+    auto queue_state = GetQueueState(queue);
 
     if (pPool && queue_state) {
         if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCB->commandBuffer), "VUID-vkQueueSubmit-pCommandBuffers-00074",
-                            "vkQueueSubmit: Primary command buffer 0x%" PRIx64
-                            " created in queue family %d is being submitted on queue 0x%" PRIx64 " from queue family %d.",
-                            HandleToUint64(pCB->commandBuffer), pPool->queueFamilyIndex, HandleToUint64(queue),
-                            queue_state->queueFamilyIndex);
+                            "vkQueueSubmit: Primary command buffer %s created in queue family %d is being submitted on queue %s "
+                            "from queue family %d.",
+                            dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(), pPool->queueFamilyIndex,
+                            dev_data->report_data->FormatHandle(queue).c_str(), queue_state->queueFamilyIndex);
         }
 
         // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
         for (auto object : pCB->object_bindings) {
             if (object.type == kVulkanObjectTypeImage) {
-                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
+                auto image_state = GetImageState(reinterpret_cast<VkImage &>(object.handle));
                 if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
                     skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
                                                   image_state->createInfo.pQueueFamilyIndices);
                 }
             } else if (object.type == kVulkanObjectTypeBuffer) {
-                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
+                auto buffer_state = GetBufferState(reinterpret_cast<VkBuffer &>(object.handle));
                 if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
                     skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
                                                   buffer_state->createInfo.pQueueFamilyIndices);
@@ -2884,9 +2924,9 @@
     return skip;
 }
 
-static bool ValidatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count,
-                                              QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
-                                              QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) {
+bool CoreChecks::ValidatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count,
+                                                   QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
+                                                   QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) {
     // Track in-use for resources off of primary and any secondary CBs
     bool skip = false;
 
@@ -2905,11 +2945,11 @@
             !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
                     "VUID-vkQueueSubmit-pCommandBuffers-00073",
-                    "Commandbuffer 0x%" PRIx64 " was submitted with secondary buffer 0x%" PRIx64
-                    " but that buffer has subsequently been bound to primary cmd buffer 0x%" PRIx64
-                    " and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
-                    HandleToUint64(pCB->commandBuffer), HandleToUint64(pSubCB->commandBuffer),
-                    HandleToUint64(pSubCB->primaryCommandBuffer));
+                    "Commandbuffer %s was submitted with secondary buffer %s but that buffer has subsequently been bound to "
+                    "primary cmd buffer %s and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
+                    dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(),
+                    dev_data->report_data->FormatHandle(pSubCB->commandBuffer).c_str(),
+                    dev_data->report_data->FormatHandle(pSubCB->primaryCommandBuffer).c_str());
         }
     }
 
@@ -2919,7 +2959,7 @@
     return skip;
 }
 
-static bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
+bool CoreChecks::ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
     bool skip = false;
 
     if (pFence && pFence->scope == kSyncScopeInternal) {
@@ -2928,7 +2968,8 @@
             // "VUID-vkAcquireNextImageKHR-fence-01287"
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
                             HandleToUint64(pFence->fence), kVUID_Core_DrawState_InvalidFence,
-                            "Fence 0x%" PRIx64 " is already in use by another submission.", HandleToUint64(pFence->fence));
+                            "Fence %s is already in use by another submission.",
+                            dev_data->report_data->FormatHandle(pFence->fence).c_str());
         }
 
         else if (pFence->state == FENCE_RETIRED) {
@@ -2936,19 +2977,20 @@
             // "VUID-vkAcquireNextImageKHR-fence-01287"
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
                             HandleToUint64(pFence->fence), kVUID_Core_MemTrack_FenceState,
-                            "Fence 0x%" PRIx64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
-                            HandleToUint64(pFence->fence));
+                            "Fence %s submitted in SIGNALED state.  Fences must be reset before being submitted",
+                            dev_data->report_data->FormatHandle(pFence->fence).c_str());
         }
     }
 
     return skip;
 }
 
-static void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
-                                      VkFence fence) {
+void CoreChecks::PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence,
+                                           VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
     uint64_t early_retire_seq = 0;
-    auto pQueue = GetQueueState(dev_data, queue);
-    auto pFence = GetFenceNode(dev_data, fence);
+    auto pQueue = GetQueueState(queue);
+    auto pFence = GetFenceNode(fence);
 
     if (pFence) {
         if (pFence->scope == kSyncScopeInternal) {
@@ -2964,14 +3006,14 @@
         } else {
             // Retire work up until this fence early, we will not see the wait that corresponds to this signal
             early_retire_seq = pQueue->seq + pQueue->submissions.size();
-            if (!dev_data->external_sync_warning) {
-                dev_data->external_sync_warning = true;
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+            if (!device_data->external_sync_warning) {
+                device_data->external_sync_warning = true;
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
                         HandleToUint64(fence), kVUID_Core_DrawState_QueueForwardProgress,
-                        "vkQueueSubmit(): Signaling external fence 0x%" PRIx64 " on queue 0x%" PRIx64
-                        " will disable validation of preceding command buffer lifecycle states and the in-use status of associated "
-                        "objects.",
-                        HandleToUint64(fence), HandleToUint64(queue));
+                        "vkQueueSubmit(): Signaling external fence %s on queue %s will disable validation of preceding command "
+                        "buffer lifecycle states and the in-use status of associated objects.",
+                        device_data->report_data->FormatHandle(fence).c_str(),
+                        device_data->report_data->FormatHandle(queue).c_str());
             }
         }
     }
@@ -2985,7 +3027,7 @@
         vector<VkSemaphore> semaphore_externals;
         for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
             VkSemaphore semaphore = submit->pWaitSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 if (pSemaphore->scope == kSyncScopeInternal) {
                     if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
@@ -3005,7 +3047,7 @@
         }
         for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
             VkSemaphore semaphore = submit->pSignalSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 if (pSemaphore->scope == kSyncScopeInternal) {
                     pSemaphore->signaler.first = queue;
@@ -3016,31 +3058,32 @@
                 } else {
                     // Retire work up until this submit early, we will not see the wait that corresponds to this signal
                     early_retire_seq = std::max(early_retire_seq, pQueue->seq + pQueue->submissions.size() + 1);
-                    if (!dev_data->external_sync_warning) {
-                        dev_data->external_sync_warning = true;
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                "vkQueueSubmit(): Signaling external semaphore 0x%" PRIx64 " on queue 0x%" PRIx64
-                                " will disable validation of preceding command buffer lifecycle states and the in-use status of "
-                                "associated objects.",
-                                HandleToUint64(semaphore), HandleToUint64(queue));
+                    if (!device_data->external_sync_warning) {
+                        device_data->external_sync_warning = true;
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
+                                VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, HandleToUint64(semaphore),
+                                kVUID_Core_DrawState_QueueForwardProgress,
+                                "vkQueueSubmit(): Signaling external semaphore %s on queue %s will disable validation of preceding "
+                                "command buffer lifecycle states and the in-use status of associated objects.",
+                                device_data->report_data->FormatHandle(semaphore).c_str(),
+                                device_data->report_data->FormatHandle(queue).c_str());
                     }
                 }
             }
         }
         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
-            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
+            auto cb_node = GetCBNode(submit->pCommandBuffers[i]);
             if (cb_node) {
                 cbs.push_back(submit->pCommandBuffers[i]);
                 for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
                     cbs.push_back(secondaryCmdBuffer->commandBuffer);
-                    UpdateCmdBufImageLayouts(dev_data, secondaryCmdBuffer);
-                    IncrementResources(dev_data, secondaryCmdBuffer);
-                    RecordQueuedQFOTransfers(dev_data, secondaryCmdBuffer);
+                    UpdateCmdBufImageLayouts(device_data, secondaryCmdBuffer);
+                    IncrementResources(device_data, secondaryCmdBuffer);
+                    RecordQueuedQFOTransfers(device_data, secondaryCmdBuffer);
                 }
-                UpdateCmdBufImageLayouts(dev_data, cb_node);
-                IncrementResources(dev_data, cb_node);
-                RecordQueuedQFOTransfers(dev_data, cb_node);
+                UpdateCmdBufImageLayouts(device_data, cb_node);
+                IncrementResources(device_data, cb_node);
+                RecordQueuedQFOTransfers(device_data, cb_node);
             }
         }
         pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals, semaphore_externals,
@@ -3048,14 +3091,18 @@
     }
 
     if (early_retire_seq) {
-        RetireWorkOnQueue(dev_data, pQueue, early_retire_seq);
+        RetireWorkOnQueue(device_data, pQueue, early_retire_seq);
+    }
+
+    if (GetEnables()->gpu_validation) {
+        GpuPostCallQueueSubmit(device_data, queue, submitCount, pSubmits, fence);
     }
 }
 
-static bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
-                                       VkFence fence) {
-    auto pFence = GetFenceNode(dev_data, fence);
-    bool skip = ValidateFenceForSubmit(dev_data, pFence);
+bool CoreChecks::PreCallValidateQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    auto pFence = GetFenceNode(fence);
+    bool skip = ValidateFenceForSubmit(device_data, pFence);
     if (skip) {
         return true;
     }
@@ -3070,18 +3117,20 @@
         const VkSubmitInfo *submit = &pSubmits[submit_idx];
         for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
             skip |= ValidateStageMaskGsTsEnables(
-                dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()", "VUID-VkSubmitInfo-pWaitDstStageMask-00076",
+                device_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()", "VUID-VkSubmitInfo-pWaitDstStageMask-00076",
                 "VUID-VkSubmitInfo-pWaitDstStageMask-00077", "VUID-VkSubmitInfo-pWaitDstStageMask-02089",
                 "VUID-VkSubmitInfo-pWaitDstStageMask-02090");
             VkSemaphore semaphore = submit->pWaitSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore && (pSemaphore->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
                 if (unsignaled_semaphores.count(semaphore) ||
                     (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                    HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                    "Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
-                                    HandleToUint64(queue), HandleToUint64(semaphore));
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
+                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
+                                "Queue %s is waiting on semaphore %s that has no way to be signaled.",
+                                device_data->report_data->FormatHandle(queue).c_str(),
+                                device_data->report_data->FormatHandle(semaphore).c_str());
                 } else {
                     signaled_semaphores.erase(semaphore);
                     unsignaled_semaphores.insert(semaphore);
@@ -3093,15 +3142,17 @@
         }
         for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
             VkSemaphore semaphore = submit->pSignalSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore && (pSemaphore->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
                 if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                    HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                    "Queue 0x%" PRIx64 " is signaling semaphore 0x%" PRIx64
-                                    " that was previously signaled by queue 0x%" PRIx64
-                                    " but has not since been waited on by any queue.",
-                                    HandleToUint64(queue), HandleToUint64(semaphore), HandleToUint64(pSemaphore->signaler.first));
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
+                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
+                                "Queue %s is signaling semaphore %s that was previously signaled by queue %s but has not since "
+                                "been waited on by any queue.",
+                                device_data->report_data->FormatHandle(queue).c_str(),
+                                device_data->report_data->FormatHandle(semaphore).c_str(),
+                                device_data->report_data->FormatHandle(pSemaphore->signaler.first).c_str());
                 } else {
                     unsignaled_semaphores.erase(semaphore);
                     signaled_semaphores.insert(semaphore);
@@ -3112,14 +3163,14 @@
         QFOTransferCBScoreboards<VkBufferMemoryBarrier> qfo_buffer_scoreboards;
 
         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
-            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
+            auto cb_node = GetCBNode(submit->pCommandBuffers[i]);
             if (cb_node) {
-                skip |= ValidateCmdBufImageLayouts(dev_data, cb_node, dev_data->imageLayoutMap, localImageLayoutMap);
+                skip |= ValidateCmdBufImageLayouts(device_data, cb_node, device_data->imageLayoutMap, localImageLayoutMap);
                 current_cmds.push_back(submit->pCommandBuffers[i]);
                 skip |= ValidatePrimaryCommandBufferState(
-                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]),
+                    device_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]),
                     &qfo_image_scoreboards, &qfo_buffer_scoreboards);
-                skip |= ValidateQueueFamilyIndices(dev_data, cb_node, queue);
+                skip |= ValidateQueueFamilyIndices(device_data, cb_node, queue);
 
                 // Potential early exit here as bad object state may crash in delayed function calls
                 if (skip) {
@@ -3142,94 +3193,582 @@
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    unique_lock_t lock(global_lock);
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+// Android-specific validation that uses types defined only on Android and only for NDK versions
+// that support the VK_ANDROID_external_memory_android_hardware_buffer extension.
+// This chunk could move into a seperate core_validation_android.cpp file... ?
 
-    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
-    lock.unlock();
+// clang-format off
 
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+// Map external format and usage flags to/from equivalent Vulkan flags
+// (Tables as of v1.1.92)
 
-    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
+// AHardwareBuffer Format                       Vulkan Format
+// ======================                       =============
+// AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM        VK_FORMAT_R8G8B8A8_UNORM
+// AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM        VK_FORMAT_R8G8B8A8_UNORM
+// AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM          VK_FORMAT_R8G8B8_UNORM
+// AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM          VK_FORMAT_R5G6B5_UNORM_PACK16
+// AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT    VK_FORMAT_R16G16B16A16_SFLOAT
+// AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM     VK_FORMAT_A2B10G10R10_UNORM_PACK32
+// AHARDWAREBUFFER_FORMAT_D16_UNORM             VK_FORMAT_D16_UNORM
+// AHARDWAREBUFFER_FORMAT_D24_UNORM             VK_FORMAT_X8_D24_UNORM_PACK32
+// AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT     VK_FORMAT_D24_UNORM_S8_UINT
+// AHARDWAREBUFFER_FORMAT_D32_FLOAT             VK_FORMAT_D32_SFLOAT
+// AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT     VK_FORMAT_D32_SFLOAT_S8_UINT
+// AHARDWAREBUFFER_FORMAT_S8_UINT               VK_FORMAT_S8_UINT
 
-    lock.lock();
-    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
-    lock.unlock();
-    return result;
-}
+// The AHARDWAREBUFFER_FORMAT_* are an enum in the NDK headers, but get passed in to Vulkan
+// as uint32_t. Casting the enums here avoids scattering casts around in the code.
+std::map<uint32_t, VkFormat> ahb_format_map_a2v = {
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,        VK_FORMAT_R8G8B8A8_UNORM },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,        VK_FORMAT_R8G8B8A8_UNORM },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,          VK_FORMAT_R8G8B8_UNORM },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,          VK_FORMAT_R5G6B5_UNORM_PACK16 },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,    VK_FORMAT_R16G16B16A16_SFLOAT },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,     VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_D16_UNORM,             VK_FORMAT_D16_UNORM },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM,             VK_FORMAT_X8_D24_UNORM_PACK32 },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,     VK_FORMAT_D24_UNORM_S8_UINT },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT,             VK_FORMAT_D32_SFLOAT },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,     VK_FORMAT_D32_SFLOAT_S8_UINT },
+    { (uint32_t)AHARDWAREBUFFER_FORMAT_S8_UINT,               VK_FORMAT_S8_UINT }
+};
 
-static bool PreCallValidateAllocateMemory(layer_data *dev_data) {
+// AHardwareBuffer Usage                        Vulkan Usage or Creation Flag (Intermixed - Aargh!)
+// =====================                        =================================================== 
+// None                                         VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+// None                                         VK_IMAGE_USAGE_TRANSFER_DST_BIT
+// AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      VK_IMAGE_USAGE_SAMPLED_BIT
+// AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
+// AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+// AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP           VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
+// AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE    None 
+// AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      VK_IMAGE_CREATE_PROTECTED_BIT
+// None                                         VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
+// None                                         VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
+
+// Same casting rationale. De-mixing the table to prevent type confusion and aliasing 
+std::map<uint64_t, VkImageUsageFlags> ahb_usage_map_a2v = {
+    { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,    (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) },
+    { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT,     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT },
+    { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE,  0 },   // No equivalent 
+};
+
+std::map<uint64_t, VkImageCreateFlags> ahb_create_map_a2v = {
+    { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP,         VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT },
+    { (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT,    VK_IMAGE_CREATE_PROTECTED_BIT },
+    { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE,  0 },   // No equivalent 
+};
+
+std::map<VkImageUsageFlags, uint64_t> ahb_usage_map_v2a = {
+    { VK_IMAGE_USAGE_SAMPLED_BIT,           (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
+    { VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
+    { VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT  },
+};
+
+std::map<VkImageCreateFlags, uint64_t> ahb_create_map_v2a = {
+    { VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP },
+    { VK_IMAGE_CREATE_PROTECTED_BIT,        (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT },
+};
+
+// clang-format on
+
+//
+// AHB-extension new APIs
+//
+bool CoreChecks::PreCallValidateGetAndroidHardwareBufferProperties(VkDevice device, const struct AHardwareBuffer *buffer,
+                                                                   VkAndroidHardwareBufferPropertiesANDROID *pProperties) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), kVUIDUndefined,
-                        "Number of currently valid memory objects is not less than the maximum allowed (%u).",
-                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount);
+    //  buffer must be a valid Android hardware buffer object with at least one of the AHARDWAREBUFFER_USAGE_GPU_* usage flags.
+    AHardwareBuffer_Desc ahb_desc;
+    AHardwareBuffer_describe(buffer, &ahb_desc);
+    uint32_t required_flags = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                              AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+                              AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
+    if (0 == (ahb_desc.usage & required_flags)) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device_data->device), "VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884",
+                        "vkGetAndroidHardwareBufferPropertiesANDROID: The AHardwareBuffer's AHardwareBuffer_Desc.usage (0x%" PRIx64
+                        ") does not have any AHARDWAREBUFFER_USAGE_GPU_* flags set.",
+                        ahb_desc.usage);
     }
     return skip;
 }
 
-static void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
-    AddMemObjInfo(dev_data, dev_data->device, *pMemory, pAllocateInfo);
+void CoreChecks::PostCallRecordGetAndroidHardwareBufferProperties(VkDevice device, const struct AHardwareBuffer *buffer,
+                                                                  VkAndroidHardwareBufferPropertiesANDROID *pProperties,
+                                                                  VkResult result) {
+    if (VK_SUCCESS != result) return;
+    auto ahb_format_props = lvl_find_in_chain<VkAndroidHardwareBufferFormatPropertiesANDROID>(pProperties->pNext);
+    if (ahb_format_props) {
+        auto ext_formats = GetAHBExternalFormatsSet();
+        ext_formats->insert(ahb_format_props->externalFormat);
+    }
+}
+
+bool CoreChecks::PreCallValidateGetMemoryAndroidHardwareBuffer(VkDevice device,
+                                                               const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
+                                                               struct AHardwareBuffer **pBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(pInfo->memory);
+
+    // VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must have been included in
+    // VkExportMemoryAllocateInfoKHR::handleTypes when memory was created.
+    if (!mem_info->is_export ||
+        (0 == (mem_info->export_handle_type_flags & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882",
+                        "vkGetMemoryAndroidHardwareBufferANDROID: The VkDeviceMemory (%s) was not allocated for export, or the "
+                        "export handleTypes (0x%" PRIx32
+                        ") did not contain VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
+                        device_data->report_data->FormatHandle(pInfo->memory).c_str(), mem_info->export_handle_type_flags);
+    }
+
+    // If the pNext chain of the VkMemoryAllocateInfo used to allocate memory included a VkMemoryDedicatedAllocateInfo
+    // with non-NULL image member, then that image must already be bound to memory.
+    if (mem_info->is_dedicated && (VK_NULL_HANDLE != mem_info->dedicated_image)) {
+        auto image_state = GetImageState(mem_info->dedicated_image);
+        if ((nullptr == image_state) || (0 == (image_state->GetBoundMemory().count(pInfo->memory)))) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883",
+                            "vkGetMemoryAndroidHardwareBufferANDROID: The VkDeviceMemory (%s) was allocated using a dedicated "
+                            "image (%s), but that image is not bound to the VkDeviceMemory object.",
+                            device_data->report_data->FormatHandle(pInfo->memory).c_str(),
+                            device_data->report_data->FormatHandle(mem_info->dedicated_image).c_str());
+        }
+    }
+
+    return skip;
+}
+
+//
+// AHB-specific validation within non-AHB APIs
+//
+bool CoreChecks::ValidateAllocateMemoryANDROID(layer_data *dev_data, const VkMemoryAllocateInfo *alloc_info) {
+    bool skip = false;
+    auto import_ahb_info = lvl_find_in_chain<VkImportAndroidHardwareBufferInfoANDROID>(alloc_info->pNext);
+    auto exp_mem_alloc_info = lvl_find_in_chain<VkExportMemoryAllocateInfo>(alloc_info->pNext);
+    auto mem_ded_alloc_info = lvl_find_in_chain<VkMemoryDedicatedAllocateInfo>(alloc_info->pNext);
+
+    if ((import_ahb_info) && (NULL != import_ahb_info->buffer)) {
+        // This is an import with handleType of VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
+        AHardwareBuffer_Desc ahb_desc = {};
+        AHardwareBuffer_describe(import_ahb_info->buffer, &ahb_desc);
+
+        //  If buffer is not NULL, it must be a valid Android hardware buffer object with AHardwareBuffer_Desc::format and
+        //  AHardwareBuffer_Desc::usage compatible with Vulkan as described in Android Hardware Buffers.
+        //
+        //  BLOB & GPU_DATA_BUFFER combo specifically allowed
+        if ((AHARDWAREBUFFER_FORMAT_BLOB != ahb_desc.format) || (0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
+            // Otherwise, must be a combination from the AHardwareBuffer Format and Usage Equivalence tables
+            // Usage must have at least one bit from the table. It may have additional bits not in the table
+            uint64_t ahb_equiv_usage_bits = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                                            AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+                                            AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+            if ((0 == (ahb_desc.usage & ahb_equiv_usage_bits)) || (0 == ahb_format_map_a2v.count(ahb_desc.format))) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881",
+                                "vkAllocateMemory: The AHardwareBuffer_Desc's format ( %u ) and/or usage ( 0x%" PRIx64
+                                " ) are not compatible with Vulkan.",
+                                ahb_desc.format, ahb_desc.usage);
+            }
+        }
+
+        // Collect external buffer info
+        VkPhysicalDeviceExternalBufferInfo pdebi = {};
+        pdebi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO;
+        pdebi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+        if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
+            pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
+        }
+        if (AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT & ahb_desc.usage) {
+            pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT];
+        }
+        VkExternalBufferProperties ext_buf_props = {};
+        ext_buf_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES;
+
+        instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->instance_data->instance), layer_data_map);
+        instance_data->instance_dispatch_table.GetPhysicalDeviceExternalBufferProperties(dev_data->physical_device, &pdebi,
+                                                                                         &ext_buf_props);
+
+        // Collect external format info
+        VkPhysicalDeviceExternalImageFormatInfo pdeifi = {};
+        pdeifi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+        pdeifi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+        VkPhysicalDeviceImageFormatInfo2 pdifi2 = {};
+        pdifi2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+        pdifi2.pNext = &pdeifi;
+        if (0 < ahb_format_map_a2v.count(ahb_desc.format)) pdifi2.format = ahb_format_map_a2v[ahb_desc.format];
+        pdifi2.type = VK_IMAGE_TYPE_2D;           // Seems likely
+        pdifi2.tiling = VK_IMAGE_TILING_OPTIMAL;  // Ditto
+        if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
+            pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
+        }
+        if (AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT & ahb_desc.usage) {
+            pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT];
+        }
+        if (AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP & ahb_desc.usage) {
+            pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP];
+        }
+        if (AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT & ahb_desc.usage) {
+            pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT];
+        }
+
+        VkExternalImageFormatProperties ext_img_fmt_props = {};
+        ext_img_fmt_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
+        VkImageFormatProperties2 ifp2 = {};
+        ifp2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+        ifp2.pNext = &ext_img_fmt_props;
+
+        VkResult fmt_lookup_result = GetPDImageFormatProperties2(&pdifi2, &ifp2);
+
+        //  If buffer is not NULL, Android hardware buffers must be supported for import, as reported by
+        //  VkExternalImageFormatProperties or VkExternalBufferProperties.
+        if (0 == (ext_buf_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) {
+            if ((VK_SUCCESS != fmt_lookup_result) || (0 == (ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures &
+                                                            VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT))) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01880",
+                                "vkAllocateMemory: Neither the VkExternalImageFormatProperties nor the VkExternalBufferProperties "
+                                "structs for the AHardwareBuffer include the VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT flag.");
+            }
+        }
+
+        // Retrieve buffer and format properties of the provided AHardwareBuffer
+        VkAndroidHardwareBufferFormatPropertiesANDROID ahb_format_props = {};
+        ahb_format_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
+        VkAndroidHardwareBufferPropertiesANDROID ahb_props = {};
+        ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
+        ahb_props.pNext = &ahb_format_props;
+        dev_data->device_dispatch_table.GetAndroidHardwareBufferPropertiesANDROID(dev_data->device, import_ahb_info->buffer,
+                                                                                  &ahb_props);
+
+        // allocationSize must be the size returned by vkGetAndroidHardwareBufferPropertiesANDROID for the Android hardware buffer
+        if (alloc_info->allocationSize != ahb_props.allocationSize) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-allocationSize-02383",
+                            "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
+                            "struct, allocationSize (%" PRId64
+                            ") does not match the AHardwareBuffer's reported allocationSize (%" PRId64 ").",
+                            alloc_info->allocationSize, ahb_props.allocationSize);
+        }
+
+        // memoryTypeIndex must be one of those returned by vkGetAndroidHardwareBufferPropertiesANDROID for the AHardwareBuffer
+        // Note: memoryTypeIndex is an index, memoryTypeBits is a bitmask
+        uint32_t mem_type_bitmask = 1 << alloc_info->memoryTypeIndex;
+        if (0 == (mem_type_bitmask & ahb_props.memoryTypeBits)) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385",
+                            "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
+                            "struct, memoryTypeIndex (%" PRId32
+                            ") does not correspond to a bit set in AHardwareBuffer's reported "
+                            "memoryTypeBits bitmask (0x%" PRIx32 ").",
+                            alloc_info->memoryTypeIndex, ahb_props.memoryTypeBits);
+        }
+
+        // Checks for allocations without a dedicated allocation requirement
+        if ((nullptr == mem_ded_alloc_info) || (VK_NULL_HANDLE == mem_ded_alloc_info->image)) {
+            // the Android hardware buffer must have a format of AHARDWAREBUFFER_FORMAT_BLOB and a usage that includes
+            // AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER
+            if (((uint64_t)AHARDWAREBUFFER_FORMAT_BLOB != ahb_format_props.externalFormat) ||
+                (0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02384",
+                    "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
+                    "struct without a dedicated allocation requirement, while the AHardwareBuffer's external format (0x%" PRIx64
+                    ") is not AHARDWAREBUFFER_FORMAT_BLOB or usage (0x%" PRIx64
+                    ") does not include AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER.",
+                    ahb_format_props.externalFormat, ahb_desc.usage);
+            }
+        } else {  // Checks specific to import with a dedicated allocation requirement
+            VkImageCreateInfo *ici = &(GetImageState(mem_ded_alloc_info->image)->createInfo);
+
+            // The Android hardware buffer's usage must include at least one of AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT or
+            // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
+            if (0 == (ahb_desc.usage & (AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE))) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02386",
+                    "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID and a "
+                    "dedicated allocation requirement, while the AHardwareBuffer's usage (0x%" PRIx64
+                    ") contains neither AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT nor AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.",
+                    ahb_desc.usage);
+            }
+
+            //  the format of image must be VK_FORMAT_UNDEFINED or the format returned by
+            //  vkGetAndroidHardwareBufferPropertiesANDROID
+            if ((ici->format != ahb_format_props.format) && (VK_FORMAT_UNDEFINED != ici->format)) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02387",
+                                "vkAllocateMemory: VkMemoryAllocateInfo struct with chained "
+                                "VkImportAndroidHardwareBufferInfoANDROID, the dedicated allocation image's "
+                                "format (%s) is not VK_FORMAT_UNDEFINED and does not match the AHardwareBuffer's format (%s).",
+                                string_VkFormat(ici->format), string_VkFormat(ahb_format_props.format));
+            }
+
+            // The width, height, and array layer dimensions of image and the Android hardwarebuffer must be identical
+            if ((ici->extent.width != ahb_desc.width) || (ici->extent.height != ahb_desc.height) ||
+                (ici->arrayLayers != ahb_desc.layers)) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02388",
+                                "vkAllocateMemory: VkMemoryAllocateInfo struct with chained "
+                                "VkImportAndroidHardwareBufferInfoANDROID, the dedicated allocation image's "
+                                "width, height, and arrayLayers (%" PRId32 " %" PRId32 " %" PRId32
+                                ") do not match those of the AHardwareBuffer (%" PRId32 " %" PRId32 " %" PRId32 ").",
+                                ici->extent.width, ici->extent.height, ici->arrayLayers, ahb_desc.width, ahb_desc.height,
+                                ahb_desc.layers);
+            }
+
+            // If the Android hardware buffer's usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, the image must
+            // have either a full mipmap chain or exactly 1 mip level.
+            //
+            // NOTE! The language of this VUID contradicts the language in the spec (1.1.93), which says "The
+            // AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE flag does not correspond to a Vulkan image usage or creation flag. Instead,
+            // its presence indicates that the Android hardware buffer contains a complete mipmap chain, and its absence indicates
+            // that the Android hardware buffer contains only a single mip level."
+            //
+            // TODO: This code implements the VUID's meaning, but it seems likely that the spec text is actually correct.
+            // Clarification requested.
+            if ((ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE) && (ici->mipLevels != 1) &&
+                (ici->mipLevels != FullMipChainLevels(ici->extent))) {
+                skip |=
+                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02389",
+                            "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID, "
+                            "usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE but mipLevels (%" PRId32
+                            ") is neither 1 nor full mip "
+                            "chain levels (%" PRId32 ").",
+                            ici->mipLevels, FullMipChainLevels(ici->extent));
+            }
+
+            // each bit set in the usage of image must be listed in AHardwareBuffer Usage Equivalence, and if there is a
+            // corresponding AHARDWAREBUFFER_USAGE bit listed that bit must be included in the Android hardware buffer's
+            // AHardwareBuffer_Desc::usage
+            if (ici->usage &
+                ~(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
+                skip |=
+                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02390",
+                            "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID, "
+                            "dedicated image usage bits include one or more with no AHardwareBuffer equivalent.");
+            }
+
+            bool illegal_usage = false;
+            std::vector<VkImageUsageFlags> usages = {VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
+                                                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT};
+            for (VkImageUsageFlags ubit : usages) {
+                if (ici->usage & ubit) {
+                    uint64_t ahb_usage = ahb_usage_map_v2a[ubit];
+                    if (0 == (ahb_usage & ahb_desc.usage)) illegal_usage = true;
+                }
+            }
+            if (illegal_usage) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-02390",
+                                "vkAllocateMemory: VkMemoryAllocateInfo struct with chained "
+                                "VkImportAndroidHardwareBufferInfoANDROID, one or more AHardwareBuffer usage bits equivalent to "
+                                "the provided image's usage bits are missing from AHardwareBuffer_Desc.usage.");
+            }
+        }
+    } else {  // Not an import
+        if ((exp_mem_alloc_info) && (mem_ded_alloc_info) &&
+            (0 != (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID & exp_mem_alloc_info->handleTypes)) &&
+            (VK_NULL_HANDLE != mem_ded_alloc_info->image)) {
+            // This is an Android HW Buffer export
+            if (0 != alloc_info->allocationSize) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-01874",
+                                "vkAllocateMemory: pNext chain indicates a dedicated Android Hardware Buffer export allocation, "
+                                "but allocationSize is non-zero.");
+            }
+        } else {
+            if (0 == alloc_info->allocationSize) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(dev_data->device), "VUID-VkMemoryAllocateInfo-pNext-01874",
+                    "vkAllocateMemory: pNext chain does not indicate a dedicated export allocation, but allocationSize is 0.");
+            };
+        }
+    }
+    return skip;
+}
+
+bool CoreChecks::ValidateGetImageMemoryRequirements2ANDROID(layer_data *dev_data, const VkImage image) {
+    bool skip = false;
+
+    IMAGE_STATE *image_state = GetImageState(image);
+    if (image_state->imported_ahb && (0 == image_state->GetBoundMemory().size())) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
+                        "VUID-VkImageMemoryRequirementsInfo2-image-01897",
+                        "vkGetImageMemoryRequirements2: Attempt to query layout from an image created with "
+                        "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType, which has not yet been "
+                        "bound to memory.");
+    }
+    return skip;
+}
+
+static bool ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const debug_report_data *report_data,
+                                                                   const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
+                                                                   const VkImageFormatProperties2 *pImageFormatProperties) {
+    bool skip = false;
+    const VkAndroidHardwareBufferUsageANDROID *ahb_usage =
+        lvl_find_in_chain<VkAndroidHardwareBufferUsageANDROID>(pImageFormatProperties->pNext);
+    if (nullptr != ahb_usage) {
+        const VkPhysicalDeviceExternalImageFormatInfo *pdeifi =
+            lvl_find_in_chain<VkPhysicalDeviceExternalImageFormatInfo>(pImageFormatInfo->pNext);
+        if ((nullptr == pdeifi) || (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID != pdeifi->handleType)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868",
+                            "vkGetPhysicalDeviceImageFormatProperties2: pImageFormatProperties includes a chained "
+                            "VkAndroidHardwareBufferUsageANDROID struct, but pImageFormatInfo does not include a chained "
+                            "VkPhysicalDeviceExternalImageFormatInfo struct with handleType "
+                            "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.");
+        }
+    }
+    return skip;
+}
+
+bool CoreChecks::ValidateCreateSamplerYcbcrConversionANDROID(const layer_data *dev_data,
+                                                             const VkSamplerYcbcrConversionCreateInfo *create_info) {
+    const VkExternalFormatANDROID *ext_format_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
+    if ((nullptr != ext_format_android) && (0 != ext_format_android->externalFormat)) {
+        if (VK_FORMAT_UNDEFINED != create_info->format) {
+            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                           VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, 0,
+                           "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904",
+                           "vkCreateSamplerYcbcrConversion[KHR]: CreateInfo format is not VK_FORMAT_UNDEFINED while "
+                           "there is a chained VkExternalFormatANDROID struct.");
+        }
+    } else if (VK_FORMAT_UNDEFINED == create_info->format) {
+        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                       VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, 0,
+                       "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904",
+                       "vkCreateSamplerYcbcrConversion[KHR]: CreateInfo format is VK_FORMAT_UNDEFINED with no chained "
+                       "VkExternalFormatANDROID struct.");
+    }
+    return false;
+}
+
+void CoreChecks::RecordCreateSamplerYcbcrConversionANDROID(layer_data *dev_data,
+                                                           const VkSamplerYcbcrConversionCreateInfo *create_info,
+                                                           VkSamplerYcbcrConversion ycbcr_conversion) {
+    const VkExternalFormatANDROID *ext_format_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
+    if (ext_format_android && (0 != ext_format_android->externalFormat)) {
+        dev_data->ycbcr_conversion_ahb_fmt_map.emplace(ycbcr_conversion, ext_format_android->externalFormat);
+    }
+};
+
+void CoreChecks::RecordDestroySamplerYcbcrConversionANDROID(layer_data *dev_data, VkSamplerYcbcrConversion ycbcr_conversion) {
+    dev_data->ycbcr_conversion_ahb_fmt_map.erase(ycbcr_conversion);
+};
+
+#else  // !VK_USE_PLATFORM_ANDROID_KHR
+
+bool CoreChecks::ValidateAllocateMemoryANDROID(layer_data *dev_data, const VkMemoryAllocateInfo *alloc_info) { return false; }
+
+static bool ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const debug_report_data *report_data,
+                                                                   const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
+                                                                   const VkImageFormatProperties2 *pImageFormatProperties) {
+    return false;
+}
+
+bool CoreChecks::ValidateCreateSamplerYcbcrConversionANDROID(const layer_data *dev_data,
+                                                             const VkSamplerYcbcrConversionCreateInfo *create_info) {
+    return false;
+}
+
+bool CoreChecks::ValidateGetImageMemoryRequirements2ANDROID(layer_data *dev_data, const VkImage image) { return false; }
+
+void CoreChecks::RecordCreateSamplerYcbcrConversionANDROID(layer_data *dev_data,
+                                                           const VkSamplerYcbcrConversionCreateInfo *create_info,
+                                                           VkSamplerYcbcrConversion ycbcr_conversion){};
+
+void CoreChecks::RecordDestroySamplerYcbcrConversionANDROID(layer_data *dev_data, VkSamplerYcbcrConversion ycbcr_conversion){};
+
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+bool CoreChecks::PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    if (device_data->memObjMap.size() >= device_data->phys_dev_props.limits.maxMemoryAllocationCount) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), kVUIDUndefined,
+                        "Number of currently valid memory objects is not less than the maximum allowed (%u).",
+                        device_data->phys_dev_props.limits.maxMemoryAllocationCount);
+    }
+
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        skip |= ValidateAllocateMemoryANDROID(device_data, pAllocateInfo);
+    } else {
+        if (0 == pAllocateInfo->allocationSize) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkMemoryAllocateInfo-allocationSize-00638",
+                            "vkAllocateMemory: allocationSize is 0.");
+        };
+    }
+    // TODO: VUIDs ending in 00643, 00644, 00646, 00647, 01742, 01743, 01745, 00645, 00648, 01744
+    return skip;
+}
+
+void CoreChecks::PostCallRecordAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
+                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory, VkResult result) {
+    if (VK_SUCCESS == result) {
+        layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+        AddMemObjInfo(device_data, device, *pMemory, pAllocateInfo);
+    }
     return;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
-                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateAllocateMemory(dev_data);
-    if (!skip) {
-        lock.unlock();
-        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
-        lock.lock();
-        if (VK_SUCCESS == result) {
-            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
-        }
-    }
-    return result;
-}
-
 // For given obj node, if it is use, flag a validation error and return callback result, else return false
-bool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct, const char *caller_name,
-                            const std::string &error_code) {
+bool CoreChecks::ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
+                                        const char *caller_name, const char *error_code) {
     if (dev_data->instance_data->disabled.object_in_use) return false;
     bool skip = false;
     if (obj_node->in_use.load()) {
         skip |=
             log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_struct.type], obj_struct.handle,
-                    error_code, "Cannot call %s on %s 0x%" PRIx64 " that is currently in use by a command buffer.", caller_name,
-                    object_string[obj_struct.type], obj_struct.handle);
+                    error_code, "Cannot call %s on %s %s that is currently in use by a command buffer.", caller_name,
+                    object_string[obj_struct.type], dev_data->report_data->FormatHandle(obj_struct.handle).c_str());
     }
     return skip;
 }
 
-static bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
-    *mem_info = GetMemObjInfo(dev_data, mem);
-    *obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
-    if (dev_data->instance_data->disabled.free_memory) return false;
+bool CoreChecks::PreCallValidateFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
+    VK_OBJECT obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
     bool skip = false;
-    if (*mem_info) {
-        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, "vkFreeMemory", "VUID-vkFreeMemory-memory-00677");
+    if (mem_info) {
+        skip |= ValidateObjectNotInUse(device_data, mem_info, obj_struct, "vkFreeMemory", "VUID-vkFreeMemory-memory-00677");
     }
     return skip;
 }
 
-static void PreCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!mem) return;
+    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
+    VK_OBJECT obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
+
     // Clear mem binding for any bound objects
     for (auto obj : mem_info->obj_bindings) {
-        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle,
-                kVUID_Core_MemTrack_FreedMemRef, "VK Object 0x%" PRIx64 " still has a reference to mem obj 0x%" PRIx64,
-                HandleToUint64(obj.handle), HandleToUint64(mem_info->mem));
+        log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle,
+                kVUID_Core_MemTrack_FreedMemRef, "VK Object %s still has a reference to mem obj %s.",
+                device_data->report_data->FormatHandle(obj.handle).c_str(),
+                device_data->report_data->FormatHandle(mem_info->mem).c_str());
         BINDABLE *bindable_state = nullptr;
         switch (obj.type) {
             case kVulkanObjectTypeImage:
-                bindable_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
+                bindable_state = GetImageState(reinterpret_cast<VkImage &>(obj.handle));
                 break;
             case kVulkanObjectTypeBuffer:
-                bindable_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
+                bindable_state = GetBufferState(reinterpret_cast<VkBuffer &>(obj.handle));
                 break;
             default:
                 // Should only have buffer or image objects bound to memory
@@ -3241,24 +3780,8 @@
         bindable_state->UpdateBoundMemorySet();
     }
     // Any bound cmd buffers are now invalid
-    InvalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
-    dev_data->memObjMap.erase(mem);
-}
-
-VKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    DEVICE_MEM_INFO *mem_info = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
-    if (!skip) {
-        if (mem != VK_NULL_HANDLE) {
-            // Avoid free/alloc race by recording state change before dispatching
-            PreCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
-    }
+    InvalidateCommandBuffers(device_data, mem_info->cb_bindings, obj_struct);
+    device_data->memObjMap.erase(mem);
 }
 
 // Validate that given Map memory range is valid. This means that the memory should not already be mapped,
@@ -3281,7 +3804,8 @@
         if (mem_info->mem_range.size != 0) {
             skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                            HandleToUint64(mem), kVUID_Core_MemTrack_InvalidMap,
-                           "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIx64, HandleToUint64(mem));
+                           "VkMapMemory: Attempting to map memory on an already-mapped object %s.",
+                           dev_data->report_data->FormatHandle(mem).c_str());
         }
 
         // Validate that offset + size is within object's allocationSize
@@ -3305,8 +3829,8 @@
     return skip;
 }
 
-static void StoreMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
-    auto mem_info = GetMemObjInfo(dev_data, mem);
+void CoreChecks::StoreMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
+    auto mem_info = GetMemObjInfo(mem);
     if (mem_info) {
         mem_info->mem_range.offset = offset;
         mem_info->mem_range.size = size;
@@ -3316,9 +3840,9 @@
 // Guard value for pad data
 static char NoncoherentMemoryFillValue = 0xb;
 
-static void InitializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
-                                     void **ppData) {
-    auto mem_info = GetMemObjInfo(dev_data, mem);
+void CoreChecks::InitializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
+                                          void **ppData) {
+    auto mem_info = GetMemObjInfo(mem);
     if (mem_info) {
         mem_info->p_driver_data = *ppData;
         uint32_t index = mem_info->alloc_info.memoryTypeIndex;
@@ -3328,11 +3852,10 @@
             if (size == VK_WHOLE_SIZE) {
                 size = mem_info->alloc_info.allocationSize - offset;
             }
-            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
-            assert(SafeModulo(mem_info->shadow_pad_size, dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) ==
-                   0);
+            mem_info->shadow_pad_size = dev_data->phys_dev_props.limits.minMemoryMapAlignment;
+            assert(SafeModulo(mem_info->shadow_pad_size, dev_data->phys_dev_props.limits.minMemoryMapAlignment) == 0);
             // Ensure start of mapped region reflects hardware alignment constraints
-            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
+            uint64_t map_alignment = dev_data->phys_dev_props.limits.minMemoryMapAlignment;
 
             // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
             uint64_t start_offset = offset % map_alignment;
@@ -3356,28 +3879,27 @@
 // Verify that state for fence being waited on is appropriate. That is,
 //  a fence being waited on should not already be signaled and
 //  it should have been submitted on a queue or during acquire next image
-static inline bool VerifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
+bool CoreChecks::VerifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
     bool skip = false;
 
-    auto pFence = GetFenceNode(dev_data, fence);
+    auto pFence = GetFenceNode(fence);
     if (pFence && pFence->scope == kSyncScopeInternal) {
         if (pFence->state == FENCE_UNSIGNALED) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
-                        HandleToUint64(fence), kVUID_Core_MemTrack_FenceState,
-                        "%s called for fence 0x%" PRIx64 " which has not been submitted on a Queue or during acquire next image.",
-                        apiCall, HandleToUint64(fence));
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+                            HandleToUint64(fence), kVUID_Core_MemTrack_FenceState,
+                            "%s called for fence %s which has not been submitted on a Queue or during acquire next image.", apiCall,
+                            dev_data->report_data->FormatHandle(fence).c_str());
         }
     }
     return skip;
 }
 
-static void RetireFence(layer_data *dev_data, VkFence fence) {
-    auto pFence = GetFenceNode(dev_data, fence);
+void CoreChecks::RetireFence(layer_data *dev_data, VkFence fence) {
+    auto pFence = GetFenceNode(fence);
     if (pFence && pFence->scope == kSyncScopeInternal) {
         if (pFence->signaler.first != VK_NULL_HANDLE) {
             // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
-            RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
+            RetireWorkOnQueue(dev_data, GetQueueState(pFence->signaler.first), pFence->signaler.second);
         } else {
             // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
             // the fence as retired.
@@ -3386,21 +3908,28 @@
     }
 }
 
-static bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
-    if (dev_data->instance_data->disabled.wait_for_fences) return false;
+bool CoreChecks::PreCallValidateWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
+                                              uint64_t timeout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    // Verify fence status of submitted fences
+    if (device_data->instance_data->disabled.wait_for_fences) return false;
     bool skip = false;
-    for (uint32_t i = 0; i < fence_count; i++) {
-        skip |= VerifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
-        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
+    for (uint32_t i = 0; i < fenceCount; i++) {
+        skip |= VerifyWaitFenceState(device_data, pFences[i], "vkWaitForFences");
+        skip |= VerifyQueueStateToFence(device_data, pFences[i]);
     }
     return skip;
 }
 
-static void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
+void CoreChecks::PostCallRecordWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
+                                             uint64_t timeout, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+
     // When we know that all fences are complete we can clean/remove their CBs
-    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
-        for (uint32_t i = 0; i < fence_count; i++) {
-            RetireFence(dev_data, fences[i]);
+    if ((VK_TRUE == waitAll) || (1 == fenceCount)) {
+        for (uint32_t i = 0; i < fenceCount; i++) {
+            RetireFence(device_data, pFences[i]);
         }
     }
     // NOTE : Alternate case not handled here is when some fences have completed. In
@@ -3408,306 +3937,220 @@
     //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
-                                             uint64_t timeout) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Verify fence status of submitted fences
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
-
-    if (result == VK_SUCCESS) {
-        lock.lock();
-        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
-        lock.unlock();
-    }
-    return result;
+bool CoreChecks::PreCallValidateGetFenceStatus(VkDevice device, VkFence fence) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return VerifyWaitFenceState(device_data, fence, "vkGetFenceStatus()");
 }
 
-static bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
-    if (dev_data->instance_data->disabled.get_fence_state) return false;
-    return VerifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
+void CoreChecks::PostCallRecordGetFenceStatus(VkDevice device, VkFence fence, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RetireFence(device_data, fence);
 }
 
-static void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
-
-VKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
-    if (result == VK_SUCCESS) {
-        lock.lock();
-        PostCallRecordGetFenceStatus(dev_data, fence);
-        lock.unlock();
-    }
-    return result;
-}
-
-static void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
+void CoreChecks::RecordGetDeviceQueueState(layer_data *device_data, uint32_t queue_family_index, VkQueue queue) {
     // Add queue to tracking set only if it is new
-    auto result = dev_data->queues.emplace(queue);
-    if (result.second == true) {
-        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
+    auto queue_is_new = device_data->queues.emplace(queue);
+    if (queue_is_new.second == true) {
+        QUEUE_STATE *queue_state = &device_data->queueMap[queue];
         queue_state->queue = queue;
-        queue_state->queueFamilyIndex = q_family_index;
+        queue_state->queueFamilyIndex = queue_family_index;
         queue_state->seq = 0;
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
-    lock_guard_t lock(global_lock);
-
-    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetDeviceQueue2(VkDevice device, VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetDeviceQueue2(device, pQueueInfo, pQueue);
-    lock_guard_t lock(global_lock);
-
-    if (*pQueue != VK_NULL_HANDLE) {
-        PostCallRecordGetDeviceQueue(dev_data, pQueueInfo->queueFamilyIndex, *pQueue);
-    }
-}
-
-static bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
-    *queue_state = GetQueueState(dev_data, queue);
-    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
-    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
-}
-
-static void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
-    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    QUEUE_STATE *queue_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordQueueWaitIdle(dev_data, queue_state);
-        lock.unlock();
-    }
-    return result;
-}
-
-static bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
-    if (dev_data->instance_data->disabled.device_wait_idle) return false;
+bool CoreChecks::ValidateGetDeviceQueue(layer_data *device_data, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue,
+                                        const char *valid_qfi_vuid, const char *qfi_in_range_vuid) {
     bool skip = false;
-    for (auto &queue : dev_data->queueMap) {
-        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
+
+    skip |= ValidateDeviceQueueFamily(device_data, queueFamilyIndex, "vkGetDeviceQueue", "queueFamilyIndex", valid_qfi_vuid);
+    const auto &queue_data = device_data->queue_family_index_map.find(queueFamilyIndex);
+    if (queue_data != device_data->queue_family_index_map.end() && queue_data->second <= queueIndex) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device_data->device), qfi_in_range_vuid,
+                        "vkGetDeviceQueue: queueIndex (=%" PRIu32
+                        ") is not less than the number of queues requested from queueFamilyIndex (=%" PRIu32
+                        ") when the device was created (i.e. is not less than %" PRIu32 ").",
+                        queueIndex, queueFamilyIndex, queue_data->second);
     }
     return skip;
 }
 
-static void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
-    for (auto &queue : dev_data->queueMap) {
-        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
-    }
+bool CoreChecks::PreCallValidateGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateGetDeviceQueue(device_data, queueFamilyIndex, queueIndex, pQueue, "VUID-vkGetDeviceQueue-queueFamilyIndex-00384",
+                                  "VUID-vkGetDeviceQueue-queueIndex-00385");
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordDeviceWaitIdle(dev_data);
-        lock.unlock();
-    }
-    return result;
+void CoreChecks::PostCallRecordGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetDeviceQueueState(device_data, queueFamilyIndex, *pQueue);
 }
 
-static bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
-    *fence_node = GetFenceNode(dev_data, fence);
-    *obj_struct = {HandleToUint64(fence), kVulkanObjectTypeFence};
-    if (dev_data->instance_data->disabled.destroy_fence) return false;
+void CoreChecks::PostCallRecordGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetDeviceQueueState(device_data, pQueueInfo->queueFamilyIndex, *pQueue);
+}
+
+bool CoreChecks::PreCallValidateQueueWaitIdle(VkQueue queue) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    QUEUE_STATE *queue_state = GetQueueState(queue);
+    if (device_data->instance_data->disabled.queue_wait_idle) return false;
+    return VerifyQueueStateToSeq(device_data, queue_state, queue_state->seq + queue_state->submissions.size());
+}
+
+void CoreChecks::PostCallRecordQueueWaitIdle(VkQueue queue, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    QUEUE_STATE *queue_state = GetQueueState(queue);
+    RetireWorkOnQueue(device_data, queue_state, queue_state->seq + queue_state->submissions.size());
+}
+
+bool CoreChecks::PreCallValidateDeviceWaitIdle(VkDevice device) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (device_data->instance_data->disabled.device_wait_idle) return false;
     bool skip = false;
-    if (*fence_node) {
-        if ((*fence_node)->scope == kSyncScopeInternal && (*fence_node)->state == FENCE_INFLIGHT) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
-                            HandleToUint64(fence), "VUID-vkDestroyFence-fence-01120", "Fence 0x%" PRIx64 " is in use.",
-                            HandleToUint64(fence));
+    for (auto &queue : device_data->queueMap) {
+        skip |= VerifyQueueStateToSeq(device_data, &queue.second, queue.second.seq + queue.second.submissions.size());
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordDeviceWaitIdle(VkDevice device, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    for (auto &queue : device_data->queueMap) {
+        RetireWorkOnQueue(device_data, &queue.second, queue.second.seq + queue.second.submissions.size());
+    }
+}
+
+bool CoreChecks::PreCallValidateDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    FENCE_NODE *fence_node = GetFenceNode(fence);
+    bool skip = false;
+    if (fence_node) {
+        if (fence_node->scope == kSyncScopeInternal && fence_node->state == FENCE_INFLIGHT) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+                            HandleToUint64(fence), "VUID-vkDestroyFence-fence-01120", "Fence %s is in use.",
+                            device_data->report_data->FormatHandle(fence).c_str());
         }
     }
     return skip;
 }
 
-static void PreCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
-
-VKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Common data objects used pre & post call
-    FENCE_NODE *fence_node = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
-
-    if (!skip) {
-        // Pre-record to avoid Destroy/Create race
-        PreCallRecordDestroyFence(dev_data, fence);
-        lock.unlock();
-        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
-    }
+void CoreChecks::PreCallRecordDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!fence) return;
+    device_data->fenceMap.erase(fence);
 }
 
-static bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
-                                            VK_OBJECT *obj_struct) {
-    *sema_node = GetSemaphoreNode(dev_data, semaphore);
-    *obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
-    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
+bool CoreChecks::PreCallValidateDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(semaphore);
+    VK_OBJECT obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
+    if (device_data->instance_data->disabled.destroy_semaphore) return false;
     bool skip = false;
-    if (*sema_node) {
-        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, "vkDestroySemaphore",
+    if (sema_node) {
+        skip |= ValidateObjectNotInUse(device_data, sema_node, obj_struct, "vkDestroySemaphore",
                                        "VUID-vkDestroySemaphore-semaphore-01137");
     }
     return skip;
 }
 
-static void PreCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
-
-VKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    SEMAPHORE_NODE *sema_node;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
-    if (!skip) {
-        // Pre-record to avoid Destroy/Create race
-        PreCallRecordDestroySemaphore(dev_data, semaphore);
-        lock.unlock();
-        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
-    }
+void CoreChecks::PreCallRecordDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!semaphore) return;
+    device_data->semaphoreMap.erase(semaphore);
 }
 
-static bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
-    *event_state = GetEventNode(dev_data, event);
-    *obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
-    if (dev_data->instance_data->disabled.destroy_event) return false;
+bool CoreChecks::PreCallValidateDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    EVENT_STATE *event_state = GetEventNode(event);
+    VK_OBJECT obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
     bool skip = false;
-    if (*event_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, "vkDestroyEvent", "VUID-vkDestroyEvent-event-01145");
+    if (event_state) {
+        skip |= ValidateObjectNotInUse(device_data, event_state, obj_struct, "vkDestroyEvent", "VUID-vkDestroyEvent-event-01145");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
-    InvalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
-    dev_data->eventMap.erase(event);
+void CoreChecks::PreCallRecordDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!event) return;
+    EVENT_STATE *event_state = GetEventNode(event);
+    VK_OBJECT obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
+    InvalidateCommandBuffers(device_data, event_state->cb_bindings, obj_struct);
+    device_data->eventMap.erase(event);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    EVENT_STATE *event_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
-    if (!skip) {
-        if (event != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
-    }
-}
-
-static bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
-                                            VK_OBJECT *obj_struct) {
-    *qp_state = GetQueryPoolNode(dev_data, query_pool);
-    *obj_struct = {HandleToUint64(query_pool), kVulkanObjectTypeQueryPool};
-    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
+bool CoreChecks::PreCallValidateDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    QUERY_POOL_NODE *qp_state = GetQueryPoolNode(queryPool);
+    VK_OBJECT obj_struct = {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool};
     bool skip = false;
-    if (*qp_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, "vkDestroyQueryPool",
+    if (qp_state) {
+        skip |= ValidateObjectNotInUse(device_data, qp_state, obj_struct, "vkDestroyQueryPool",
                                        "VUID-vkDestroyQueryPool-queryPool-00793");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
-                                          VK_OBJECT obj_struct) {
-    InvalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
-    dev_data->queryPoolMap.erase(query_pool);
+void CoreChecks::PreCallRecordDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!queryPool) return;
+    QUERY_POOL_NODE *qp_state = GetQueryPoolNode(queryPool);
+    VK_OBJECT obj_struct = {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool};
+    InvalidateCommandBuffers(device_data, qp_state->cb_bindings, obj_struct);
+    device_data->queryPoolMap.erase(queryPool);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    QUERY_POOL_NODE *qp_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
-    if (!skip) {
-        if (queryPool != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
-    }
-}
-static bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
-                                               uint32_t query_count, VkQueryResultFlags flags,
-                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
+bool CoreChecks::PreCallValidateGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
+                                                    uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
+                                                    VkQueryResultFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    auto query_pool_state = dev_data->queryPoolMap.find(query_pool);
-    if (query_pool_state != dev_data->queryPoolMap.end()) {
+    auto query_pool_state = device_data->queryPoolMap.find(queryPool);
+    if (query_pool_state != device_data->queryPoolMap.end()) {
         if ((query_pool_state->second.createInfo.queryType == VK_QUERY_TYPE_TIMESTAMP) && (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
-                        "VUID-vkGetQueryPoolResults-queryType-00818",
-                        "QueryPool 0x%" PRIx64
-                        " was created with a queryType of VK_QUERY_TYPE_TIMESTAMP but flags contains VK_QUERY_RESULT_PARTIAL_BIT.",
-                        HandleToUint64(query_pool));
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
+                            "VUID-vkGetQueryPoolResults-queryType-00818",
+                            "QueryPool %s was created with a queryType of VK_QUERY_TYPE_TIMESTAMP but flags contains "
+                            "VK_QUERY_RESULT_PARTIAL_BIT.",
+                            device_data->report_data->FormatHandle(queryPool).c_str());
         }
     }
-
-    // TODO: clean this up, it's insanely wasteful.
-    for (auto cmd_buffer : dev_data->commandBufferMap) {
-        if (cmd_buffer.second->in_use.load()) {
-            for (auto query_state_pair : cmd_buffer.second->queryToStateMap) {
-                (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer.first);
-            }
-        }
-    }
-
     return skip;
 }
 
-static void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
-                                              uint32_t query_count,
-                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
-    for (uint32_t i = 0; i < query_count; ++i) {
-        QueryObject query = {query_pool, first_query + i};
-        auto qif_pair = queries_in_flight->find(query);
-        auto query_state_pair = dev_data->queryToStateMap.find(query);
-        if (query_state_pair != dev_data->queryToStateMap.end()) {
+void CoreChecks::PostCallRecordGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
+                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags,
+                                                   VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    if ((VK_SUCCESS != result) && (VK_NOT_READY != result)) return;
+    // TODO: clean this up, it's insanely wasteful.
+    unordered_map<QueryObject, std::vector<VkCommandBuffer>> queries_in_flight;
+    for (auto cmd_buffer : device_data->commandBufferMap) {
+        if (cmd_buffer.second->in_use.load()) {
+            for (auto query_state_pair : cmd_buffer.second->queryToStateMap) {
+                queries_in_flight[query_state_pair.first].push_back(cmd_buffer.first);
+            }
+        }
+    }
+    for (uint32_t i = 0; i < queryCount; ++i) {
+        QueryObject query = {queryPool, firstQuery + i};
+        auto qif_pair = queries_in_flight.find(query);
+        auto query_state_pair = device_data->queryToStateMap.find(query);
+        if (query_state_pair != device_data->queryToStateMap.end()) {
             // Available and in flight
-            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
+            if (qif_pair != queries_in_flight.end() && query_state_pair != device_data->queryToStateMap.end() &&
                 query_state_pair->second) {
                 for (auto cmd_buffer : qif_pair->second) {
-                    auto cb = GetCBNode(dev_data, cmd_buffer);
+                    auto cb = GetCBNode(cmd_buffer);
                     auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
                     if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
                         for (auto event : query_event_pair->second) {
-                            dev_data->eventMap[event].needsSignaled = true;
+                            device_data->eventMap[event].needsSignaled = true;
                         }
                     }
                 }
@@ -3716,22 +4159,6 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
-                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result =
-        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
-    lock.lock();
-    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
-    lock.unlock();
-    return result;
-}
-
 // Return true if given ranges intersect, else false
 // Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
 //  in an error so not checking that here
@@ -3739,8 +4166,8 @@
 // In the case where padding is required, if an alias is encountered then a validation error is reported and skip
 //  may be set by the callback function so caller should merge in skip value if padding case is possible.
 // This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
-static bool RangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
-                            bool skip_checks) {
+bool CoreChecks::RangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
+                                 bool skip_checks) {
     *skip = false;
     auto r1_start = range1->start;
     auto r1_end = range1->end;
@@ -3748,7 +4175,7 @@
     auto r2_end = range2->end;
     VkDeviceSize pad_align = 1;
     if (range1->linear != range2->linear) {
-        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
+        pad_align = dev_data->phys_dev_props.limits.bufferImageGranularity;
     }
     if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
     if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
@@ -3762,17 +4189,17 @@
         auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
         *skip |= log_msg(
             dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, kVUID_Core_MemTrack_InvalidAliasing,
-            "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
-            " which may indicate a bug. For further info refer to the Buffer-Image Granularity section of the Vulkan "
-            "specification. "
+            "%s %s %s is aliased with %s %s %s which may indicate a bug. For further info refer to the Buffer-Image Granularity "
+            "section of the Vulkan specification. "
             "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/xhtml/vkspec.html#resources-bufferimagegranularity)",
-            r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
+            r1_linear_str, r1_type_str, dev_data->report_data->FormatHandle(range1->handle).c_str(), r2_linear_str, r2_type_str,
+            dev_data->report_data->FormatHandle(range2->handle).c_str());
     }
     // Ranges intersect
     return true;
 }
 // Simplified RangesIntersect that calls above function to check range1 for intersection with offset & end addresses
-bool RangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
+bool CoreChecks::RangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
     // Create a local MEMORY_RANGE struct to wrap offset/size
     MEMORY_RANGE range_wrap;
     // Synch linear with range1 to avoid padding and potential validation error case
@@ -3783,9 +4210,9 @@
     return RangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
 }
 
-static bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
-                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
-                                      bool is_linear, const char *api_name) {
+bool CoreChecks::ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
+                                           VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
+                                           bool is_linear, const char *api_name) {
     bool skip = false;
 
     MEMORY_RANGE range;
@@ -3809,14 +4236,14 @@
     }
 
     if (memoryOffset >= mem_info->alloc_info.allocationSize) {
-        std::string error_code =
+        const char *error_code =
             is_image ? "VUID-vkBindImageMemory-memoryOffset-01046" : "VUID-vkBindBufferMemory-memoryOffset-01031";
         skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                        HandleToUint64(mem_info->mem), error_code,
-                       "In %s, attempting to bind memory (0x%" PRIx64 ") to object (0x%" PRIx64 "), memoryOffset=0x%" PRIxLEAST64
+                       "In %s, attempting to bind memory (%s) to object (%s), memoryOffset=0x%" PRIxLEAST64
                        " must be less than the memory allocation size 0x%" PRIxLEAST64 ".",
-                       api_name, HandleToUint64(mem_info->mem), HandleToUint64(handle), memoryOffset,
-                       mem_info->alloc_info.allocationSize);
+                       api_name, dev_data->report_data->FormatHandle(mem_info->mem).c_str(),
+                       dev_data->report_data->FormatHandle(handle).c_str(), memoryOffset, mem_info->alloc_info.allocationSize);
     }
 
     return skip;
@@ -3829,8 +4256,8 @@
 // Return true if an error is flagged and the user callback returns "true", otherwise false
 // is_image indicates an image object, otherwise handle is for a buffer
 // is_linear indicates a buffer or linear image
-static void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
-                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
+void CoreChecks::InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
+                                   VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
     MEMORY_RANGE range;
 
     range.image = is_image;
@@ -3863,22 +4290,22 @@
         mem_info->bound_buffers.insert(handle);
 }
 
-static bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
-                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
-                                           const char *api_name) {
+bool CoreChecks::ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
+                                                VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
+                                                const char *api_name) {
     return ValidateInsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear, api_name);
 }
-static void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
-                                   VkMemoryRequirements mem_reqs, bool is_linear) {
+void CoreChecks::InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
+                                        VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear) {
     InsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear);
 }
 
-static bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
-                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
+bool CoreChecks::ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
+                                                 VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
     return ValidateInsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
 }
-static void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
-                                    VkMemoryRequirements mem_reqs) {
+void CoreChecks::InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
+                                         VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs) {
     InsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true);
 }
 
@@ -3900,107 +4327,59 @@
     }
 }
 
-void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
+void CoreChecks::RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
 
-void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
+void CoreChecks::RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
 
-VKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    BUFFER_STATE *buffer_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
-    if (!skip) {
-        if (buffer != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Common data objects used pre & post call
-    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    // Validate state before calling down chain, update common data if we'll be calling down chain
-    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
-    if (!skip) {
-        if (bufferView != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    IMAGE_STATE *image_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
-    if (!skip) {
-        if (image != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
-    }
-}
-
-static bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
-                                const char *funcName, std::string msgCode) {
+bool CoreChecks::ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
+                                     const char *funcName, const char *msgCode) {
     bool skip = false;
     if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
         skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                        HandleToUint64(mem_info->mem), msgCode,
                        "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
-                       "type (0x%X) of this memory object 0x%" PRIx64 ".",
-                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex, HandleToUint64(mem_info->mem));
+                       "type (0x%X) of this memory object %s.",
+                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
+                       dev_data->report_data->FormatHandle(mem_info->mem).c_str());
     }
     return skip;
 }
 
-static bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
-                                            VkDeviceSize memoryOffset, const char *api_name) {
+bool CoreChecks::ValidateBindBufferMemory(layer_data *device_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                          const char *api_name) {
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+
     bool skip = false;
     if (buffer_state) {
-        unique_lock_t lock(global_lock);
         // Track objects tied to memory
         uint64_t buffer_handle = HandleToUint64(buffer);
-        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, api_name);
+        skip = ValidateSetMemBinding(device_data, mem, buffer_handle, kVulkanObjectTypeBuffer, api_name);
         if (!buffer_state->memory_requirements_checked) {
             // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
             // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
             // vkGetBufferMemoryRequirements()
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
-                            buffer_handle, kVUID_Core_DrawState_InvalidBuffer,
-                            "%s: Binding memory to buffer 0x%" PRIx64
-                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
-                            api_name, HandleToUint64(buffer_handle));
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                        buffer_handle, kVUID_Core_DrawState_InvalidBuffer,
+                        "%s: Binding memory to buffer %s but vkGetBufferMemoryRequirements() has not been called on that buffer.",
+                        api_name, device_data->report_data->FormatHandle(buffer_handle).c_str());
             // Make the call for them so we can verify the state
-            lock.unlock();
-            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
-            lock.lock();
+            device_data->device_dispatch_table.GetBufferMemoryRequirements(device_data->device, buffer,
+                                                                           &buffer_state->requirements);
         }
 
         // Validate bound memory range information
-        const auto mem_info = GetMemObjInfo(dev_data, mem);
+        const auto mem_info = GetMemObjInfo(mem);
         if (mem_info) {
-            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements, api_name);
-            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, api_name,
+            skip |=
+                ValidateInsertBufferMemoryRange(device_data, buffer, mem_info, memoryOffset, buffer_state->requirements, api_name);
+            skip |= ValidateMemoryTypes(device_data, mem_info, buffer_state->requirements.memoryTypeBits, api_name,
                                         "VUID-vkBindBufferMemory-memory-01035");
         }
 
         // Validate memory requirements alignment
         if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                             buffer_handle, "VUID-vkBindBufferMemory-memoryOffset-01036",
                             "%s: memoryOffset is 0x%" PRIxLEAST64
                             " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
@@ -4011,7 +4390,7 @@
         if (mem_info) {
             // Validate memory requirements size
             if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                                 buffer_handle, "VUID-vkBindBufferMemory-size-01037",
                                 "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64
                                 " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
@@ -4026,480 +4405,370 @@
                 if (strcmp(api_name, "vkBindBufferMemory()") == 0) {
                     validation_error = "VUID-vkBindBufferMemory-memory-01508";
                 }
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
-                            buffer_handle, validation_error,
-                            "%s: for dedicated memory allocation 0x%" PRIxLEAST64
-                            ", VkMemoryDedicatedAllocateInfoKHR::buffer 0x%" PRIXLEAST64 " must be equal to buffer 0x%" PRIxLEAST64
-                            " and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
-                            api_name, HandleToUint64(mem), HandleToUint64(mem_info->dedicated_buffer), buffer_handle, memoryOffset);
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                                buffer_handle, validation_error,
+                                "%s: for dedicated memory allocation %s, VkMemoryDedicatedAllocateInfoKHR::buffer %s must be equal "
+                                "to buffer %s and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
+                                api_name, device_data->report_data->FormatHandle(mem).c_str(),
+                                device_data->report_data->FormatHandle(mem_info->dedicated_buffer).c_str(),
+                                device_data->report_data->FormatHandle(buffer_handle).c_str(), memoryOffset);
             }
         }
     }
     return skip;
 }
 
-static void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
-                                           VkDeviceSize memoryOffset, const char *api_name) {
-    if (buffer_state) {
-        unique_lock_t lock(global_lock);
-        // Track bound memory range information
-        auto mem_info = GetMemObjInfo(dev_data, mem);
-        if (mem_info) {
-            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
-        }
+bool CoreChecks::PreCallValidateBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    const char *api_name = "vkBindBufferMemory()";
+    return ValidateBindBufferMemory(device_data, buffer, mem, memoryOffset, api_name);
+}
 
+void CoreChecks::UpdateBindBufferMemoryState(layer_data *device_data, VkBuffer buffer, VkDeviceMemory mem,
+                                             VkDeviceSize memoryOffset) {
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    if (buffer_state) {
+        // Track bound memory range information
+        auto mem_info = GetMemObjInfo(mem);
+        if (mem_info) {
+            InsertBufferMemoryRange(device_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
+        }
         // Track objects tied to memory
         uint64_t buffer_handle = HandleToUint64(buffer);
-        SetMemBinding(dev_data, mem, buffer_state, memoryOffset, buffer_handle, kVulkanObjectTypeBuffer, api_name);
+        SetMemBinding(device_data, mem, buffer_state, memoryOffset, buffer_handle, kVulkanObjectTypeBuffer);
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    BUFFER_STATE *buffer_state;
-    {
-        unique_lock_t lock(global_lock);
-        buffer_state = GetBufferState(dev_data, buffer);
-    }
-    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset, "vkBindBufferMemory()");
-    if (!skip) {
-        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset, "vkBindBufferMemory()");
-        }
-    }
-    return result;
+void CoreChecks::PostCallRecordBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                                VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    UpdateBindBufferMemoryState(device_data, buffer, mem, memoryOffset);
 }
 
-static bool PreCallValidateBindBufferMemory2(layer_data *dev_data, std::vector<BUFFER_STATE *> *buffer_state,
-                                             uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR *pBindInfos) {
-    {
-        unique_lock_t lock(global_lock);
-        for (uint32_t i = 0; i < bindInfoCount; i++) {
-            (*buffer_state)[i] = GetBufferState(dev_data, pBindInfos[i].buffer);
-        }
-    }
-    bool skip = false;
+bool CoreChecks::PreCallValidateBindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
+                                                  const VkBindBufferMemoryInfoKHR *pBindInfos) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     char api_name[64];
+    bool skip = false;
+
     for (uint32_t i = 0; i < bindInfoCount; i++) {
         sprintf(api_name, "vkBindBufferMemory2() pBindInfos[%u]", i);
-        skip |= PreCallValidateBindBufferMemory(dev_data, pBindInfos[i].buffer, (*buffer_state)[i], pBindInfos[i].memory,
-                                                pBindInfos[i].memoryOffset, api_name);
+        skip |=
+            ValidateBindBufferMemory(device_data, pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
     }
     return skip;
 }
 
-static void PostCallRecordBindBufferMemory2(layer_data *dev_data, const std::vector<BUFFER_STATE *> &buffer_state,
-                                            uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR *pBindInfos) {
+bool CoreChecks::PreCallValidateBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount,
+                                                     const VkBindBufferMemoryInfoKHR *pBindInfos) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    char api_name[64];
+    bool skip = false;
+
     for (uint32_t i = 0; i < bindInfoCount; i++) {
-        PostCallRecordBindBufferMemory(dev_data, pBindInfos[i].buffer, buffer_state[i], pBindInfos[i].memory,
-                                       pBindInfos[i].memoryOffset, "vkBindBufferMemory2()");
+        sprintf(api_name, "vkBindBufferMemory2KHR() pBindInfos[%u]", i);
+        skip |=
+            ValidateBindBufferMemory(device_data, pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordBindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
+                                                 const VkBindBufferMemoryInfoKHR *pBindInfos, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        UpdateBindBufferMemoryState(device_data, pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset);
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
-                                                 const VkBindBufferMemoryInfoKHR *pBindInfos) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::vector<BUFFER_STATE *> buffer_state(bindInfoCount);
-    if (!PreCallValidateBindBufferMemory2(dev_data, &buffer_state, bindInfoCount, pBindInfos)) {
-        result = dev_data->dispatch_table.BindBufferMemory2(device, bindInfoCount, pBindInfos);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindBufferMemory2(dev_data, buffer_state, bindInfoCount, pBindInfos);
-        }
+void CoreChecks::PostCallRecordBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount,
+                                                    const VkBindBufferMemoryInfoKHR *pBindInfos, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        UpdateBindBufferMemoryState(device_data, pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset);
     }
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount,
-                                                    const VkBindBufferMemoryInfoKHR *pBindInfos) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::vector<BUFFER_STATE *> buffer_state(bindInfoCount);
-    if (!PreCallValidateBindBufferMemory2(dev_data, &buffer_state, bindInfoCount, pBindInfos)) {
-        result = dev_data->dispatch_table.BindBufferMemory2KHR(device, bindInfoCount, pBindInfos);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindBufferMemory2(dev_data, buffer_state, bindInfoCount, pBindInfos);
-        }
-    }
-    return result;
-}
-
-static void PostCallRecordGetBufferMemoryRequirements(layer_data *dev_data, VkBuffer buffer,
-                                                      VkMemoryRequirements *pMemoryRequirements) {
-    BUFFER_STATE *buffer_state;
-    {
-        unique_lock_t lock(global_lock);
-        buffer_state = GetBufferState(dev_data, buffer);
-    }
+void CoreChecks::RecordGetBufferMemoryRequirementsState(layer_data *device_data, VkBuffer buffer,
+                                                        VkMemoryRequirements *pMemoryRequirements) {
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
     if (buffer_state) {
         buffer_state->requirements = *pMemoryRequirements;
         buffer_state->memory_requirements_checked = true;
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
-                                                       VkMemoryRequirements *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
-    PostCallRecordGetBufferMemoryRequirements(dev_data, buffer, pMemoryRequirements);
+void CoreChecks::PostCallRecordGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
+                                                           VkMemoryRequirements *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetBufferMemoryRequirementsState(device_data, buffer, pMemoryRequirements);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR *pInfo,
-                                                        VkMemoryRequirements2KHR *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
-    PostCallRecordGetBufferMemoryRequirements(dev_data, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
+void CoreChecks::PostCallRecordGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR *pInfo,
+                                                            VkMemoryRequirements2KHR *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetBufferMemoryRequirementsState(device_data, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR *pInfo,
-                                                           VkMemoryRequirements2KHR *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetBufferMemoryRequirements2KHR(device, pInfo, pMemoryRequirements);
-    PostCallRecordGetBufferMemoryRequirements(dev_data, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
+void CoreChecks::PostCallRecordGetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR *pInfo,
+                                                               VkMemoryRequirements2KHR *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetBufferMemoryRequirementsState(device_data, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
 }
 
-static void PostCallRecordGetImageMemoryRequirements(layer_data *dev_data, VkImage image,
-                                                     VkMemoryRequirements *pMemoryRequirements) {
-    IMAGE_STATE *image_state;
-    {
-        unique_lock_t lock(global_lock);
-        image_state = GetImageState(dev_data, image);
+bool CoreChecks::ValidateGetImageMemoryRequirements2(layer_data *dev_data, const VkImageMemoryRequirementsInfo2 *pInfo) {
+    bool skip = false;
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        skip |= ValidateGetImageMemoryRequirements2ANDROID(dev_data, pInfo->image);
     }
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
+                                                            VkMemoryRequirements2 *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateGetImageMemoryRequirements2(device_data, pInfo);
+}
+
+bool CoreChecks::PreCallValidateGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
+                                                               VkMemoryRequirements2 *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateGetImageMemoryRequirements2(device_data, pInfo);
+}
+
+void CoreChecks::RecordGetImageMemoryRequiementsState(layer_data *device_data, VkImage image,
+                                                      VkMemoryRequirements *pMemoryRequirements) {
+    IMAGE_STATE *image_state = GetImageState(image);
     if (image_state) {
         image_state->requirements = *pMemoryRequirements;
         image_state->memory_requirements_checked = true;
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
-    PostCallRecordGetImageMemoryRequirements(dev_data, image, pMemoryRequirements);
+void CoreChecks::PostCallRecordGetImageMemoryRequirements(VkDevice device, VkImage image,
+                                                          VkMemoryRequirements *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetImageMemoryRequiementsState(device_data, image, pMemoryRequirements);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2KHR *pInfo,
-                                                       VkMemoryRequirements2KHR *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
-    PostCallRecordGetImageMemoryRequirements(dev_data, pInfo->image, &pMemoryRequirements->memoryRequirements);
+void CoreChecks::PostCallRecordGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
+                                                           VkMemoryRequirements2 *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetImageMemoryRequiementsState(device_data, pInfo->image, &pMemoryRequirements->memoryRequirements);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2KHR *pInfo,
-                                                          VkMemoryRequirements2KHR *pMemoryRequirements) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageMemoryRequirements2KHR(device, pInfo, pMemoryRequirements);
-    PostCallRecordGetImageMemoryRequirements(dev_data, pInfo->image, &pMemoryRequirements->memoryRequirements);
+void CoreChecks::PostCallRecordGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
+                                                              VkMemoryRequirements2 *pMemoryRequirements) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordGetImageMemoryRequiementsState(device_data, pInfo->image, &pMemoryRequirements->memoryRequirements);
 }
 
-static void PostCallRecordGetImageSparseMemoryRequirements(IMAGE_STATE *image_state, uint32_t req_count,
-                                                           VkSparseImageMemoryRequirements *reqs) {
-    image_state->get_sparse_reqs_called = true;
-    image_state->sparse_requirements.resize(req_count);
-    if (reqs) {
-        std::copy(reqs, reqs + req_count, image_state->sparse_requirements.begin());
-    }
-    for (const auto &req : image_state->sparse_requirements) {
-        if (req.formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
-            image_state->sparse_metadata_required = true;
-        }
+static void RecordGetImageSparseMemoryRequirementsState(IMAGE_STATE *image_state,
+                                                        VkSparseImageMemoryRequirements *sparse_image_memory_requirements) {
+    image_state->sparse_requirements.emplace_back(*sparse_image_memory_requirements);
+    if (sparse_image_memory_requirements->formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
+        image_state->sparse_metadata_required = true;
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL GetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pSparseMemoryRequirementCount,
-                                                            VkSparseImageMemoryRequirements *pSparseMemoryRequirements) {
-    // TODO : Implement tracking here, just passthrough initially
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageSparseMemoryRequirements(device, image, pSparseMemoryRequirementCount,
-                                                              pSparseMemoryRequirements);
-    unique_lock_t lock(global_lock);
-    auto image_state = GetImageState(dev_data, image);
-    PostCallRecordGetImageSparseMemoryRequirements(image_state, *pSparseMemoryRequirementCount, pSparseMemoryRequirements);
-}
-
-static void PostCallRecordGetImageSparseMemoryRequirements2(IMAGE_STATE *image_state, uint32_t req_count,
-                                                            VkSparseImageMemoryRequirements2KHR *reqs) {
-    // reqs is empty, so there is nothing to loop over and read.
-    if (reqs == nullptr) {
-        return;
-    }
-    std::vector<VkSparseImageMemoryRequirements> sparse_reqs(req_count);
-    // Migrate to old struct type for common handling with GetImageSparseMemoryRequirements()
-    for (uint32_t i = 0; i < req_count; ++i) {
-        assert(!reqs[i].pNext);  // TODO: If an extension is ever added here we need to handle it
-        sparse_reqs[i] = reqs[i].memoryRequirements;
-    }
-    PostCallRecordGetImageSparseMemoryRequirements(image_state, req_count, sparse_reqs.data());
-}
-
-VKAPI_ATTR void VKAPI_CALL GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR *pInfo,
-                                                             uint32_t *pSparseMemoryRequirementCount,
-                                                             VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) {
-    // TODO : Implement tracking here, just passthrough initially
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount,
-                                                               pSparseMemoryRequirements);
-    unique_lock_t lock(global_lock);
-    auto image_state = GetImageState(dev_data, pInfo->image);
-    PostCallRecordGetImageSparseMemoryRequirements2(image_state, *pSparseMemoryRequirementCount, pSparseMemoryRequirements);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetImageSparseMemoryRequirements2KHR(VkDevice device,
-                                                                const VkImageSparseMemoryRequirementsInfo2KHR *pInfo,
+void CoreChecks::PostCallRecordGetImageSparseMemoryRequirements(VkDevice device, VkImage image,
                                                                 uint32_t *pSparseMemoryRequirementCount,
-                                                                VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) {
-    // TODO : Implement tracking here, just passthrough initially
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    dev_data->dispatch_table.GetImageSparseMemoryRequirements2KHR(device, pInfo, pSparseMemoryRequirementCount,
-                                                                  pSparseMemoryRequirements);
-    unique_lock_t lock(global_lock);
-    auto image_state = GetImageState(dev_data, pInfo->image);
-    PostCallRecordGetImageSparseMemoryRequirements2(image_state, *pSparseMemoryRequirementCount, pSparseMemoryRequirements);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
-                                                                        VkImageType type, VkSampleCountFlagBits samples,
-                                                                        VkImageUsageFlags usage, VkImageTiling tiling,
-                                                                        uint32_t *pPropertyCount,
-                                                                        VkSparseImageFormatProperties *pProperties) {
-    // TODO : Implement this intercept, track sparse image format properties and make sure they are obeyed.
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    instance_data->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling,
-                                                                               pPropertyCount, pProperties);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties2(
-    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
-    VkSparseImageFormatProperties2KHR *pProperties) {
-    // TODO : Implement this intercept, track sparse image format properties and make sure they are obeyed.
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    instance_data->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount,
-                                                                                pProperties);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties2KHR(
-    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
-    VkSparseImageFormatProperties2KHR *pProperties) {
-    // TODO : Implement this intercept, track sparse image format properties and make sure they are obeyed.
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    instance_data->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties2KHR(physicalDevice, pFormatInfo, pPropertyCount,
-                                                                                   pProperties);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Common data objects used pre & post call
-    IMAGE_VIEW_STATE *image_view_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
-    if (!skip) {
-        if (imageView != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
+                                                                VkSparseImageMemoryRequirements *pSparseMemoryRequirements) {
+    auto image_state = GetImageState(image);
+    image_state->get_sparse_reqs_called = true;
+    if (!pSparseMemoryRequirements) return;
+    for (uint32_t i = 0; i < *pSparseMemoryRequirementCount; i++) {
+        RecordGetImageSparseMemoryRequirementsState(image_state, &pSparseMemoryRequirements[i]);
     }
 }
 
-static void PreCallRecordDestroyShaderModule(layer_data *dev_data, VkShaderModule shaderModule) {
-    dev_data->shaderModuleMap.erase(shaderModule);
+void CoreChecks::PostCallRecordGetImageSparseMemoryRequirements2(VkDevice device,
+                                                                 const VkImageSparseMemoryRequirementsInfo2KHR *pInfo,
+                                                                 uint32_t *pSparseMemoryRequirementCount,
+                                                                 VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) {
+    auto image_state = GetImageState(pInfo->image);
+    image_state->get_sparse_reqs_called = true;
+    if (!pSparseMemoryRequirements) return;
+    for (uint32_t i = 0; i < *pSparseMemoryRequirementCount; i++) {
+        assert(!pSparseMemoryRequirements[i].pNext);  // TODO: If an extension is ever added here we need to handle it
+        RecordGetImageSparseMemoryRequirementsState(image_state, &pSparseMemoryRequirements[i].memoryRequirements);
+    }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
-                                               const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordDestroyShaderModule(dev_data, shaderModule);
-    lock.unlock();
-
-    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
+void CoreChecks::PostCallRecordGetImageSparseMemoryRequirements2KHR(
+    VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR *pInfo, uint32_t *pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) {
+    auto image_state = GetImageState(pInfo->image);
+    image_state->get_sparse_reqs_called = true;
+    if (!pSparseMemoryRequirements) return;
+    for (uint32_t i = 0; i < *pSparseMemoryRequirementCount; i++) {
+        assert(!pSparseMemoryRequirements[i].pNext);  // TODO: If an extension is ever added here we need to handle it
+        RecordGetImageSparseMemoryRequirementsState(image_state, &pSparseMemoryRequirements[i].memoryRequirements);
+    }
 }
 
-static bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
-                                           VK_OBJECT *obj_struct) {
-    *pipeline_state = GetPipelineState(dev_data, pipeline);
-    *obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
-    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
+bool CoreChecks::PreCallValidateGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
+                                                                        const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
+                                                                        VkImageFormatProperties2 *pImageFormatProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    // Can't wrap AHB-specific validation in a device extension check here, but no harm
+    bool skip = ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(instance_data->report_data, pImageFormatInfo,
+                                                                       pImageFormatProperties);
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                           const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
+                                                                           VkImageFormatProperties2 *pImageFormatProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    // Can't wrap AHB-specific validation in a device extension check here, but no harm
+    bool skip = ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(instance_data->report_data, pImageFormatInfo,
+                                                                       pImageFormatProperties);
+    return skip;
+}
+
+void CoreChecks::PreCallRecordDestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
+                                                  const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!shaderModule) return;
+    device_data->shaderModuleMap.erase(shaderModule);
+}
+
+bool CoreChecks::PreCallValidateDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    PIPELINE_STATE *pipeline_state = GetPipelineState(pipeline);
+    VK_OBJECT obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
+    if (device_data->instance_data->disabled.destroy_pipeline) return false;
     bool skip = false;
-    if (*pipeline_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, "vkDestroyPipeline",
+    if (pipeline_state) {
+        skip |= ValidateObjectNotInUse(device_data, pipeline_state, obj_struct, "vkDestroyPipeline",
                                        "VUID-vkDestroyPipeline-pipeline-00765");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
-                                         VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!pipeline) return;
+    PIPELINE_STATE *pipeline_state = GetPipelineState(pipeline);
+    VK_OBJECT obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
     // Any bound cmd buffers are now invalid
-    InvalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
-    dev_data->pipelineMap.erase(pipeline);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    PIPELINE_STATE *pipeline_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
-    if (!skip) {
-        if (pipeline != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
+    InvalidateCommandBuffers(device_data, pipeline_state->cb_bindings, obj_struct);
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallRecordDestroyPipeline(device_data, pipeline);
     }
+    device_data->pipelineMap.erase(pipeline);
 }
 
-static void PreCallRecordDestroyPipelineLayout(layer_data *dev_data, VkPipelineLayout pipelineLayout) {
-    dev_data->pipelineLayoutMap.erase(pipelineLayout);
+void CoreChecks::PreCallRecordDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
+                                                    const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!pipelineLayout) return;
+    device_data->pipelineLayoutMap.erase(pipelineLayout);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
-                                                 const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordDestroyPipelineLayout(dev_data, pipelineLayout);
-    lock.unlock();
-
-    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
-}
-
-static bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
-                                          VK_OBJECT *obj_struct) {
-    *sampler_state = GetSamplerState(dev_data, sampler);
-    *obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
-    if (dev_data->instance_data->disabled.destroy_sampler) return false;
+bool CoreChecks::PreCallValidateDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    SAMPLER_STATE *sampler_state = GetSamplerState(sampler);
+    VK_OBJECT obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
+    if (device_data->instance_data->disabled.destroy_sampler) return false;
     bool skip = false;
-    if (*sampler_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, "vkDestroySampler",
+    if (sampler_state) {
+        skip |= ValidateObjectNotInUse(device_data, sampler_state, obj_struct, "vkDestroySampler",
                                        "VUID-vkDestroySampler-sampler-01082");
     }
     return skip;
 }
 
-static void PreCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
-                                        VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!sampler) return;
+    SAMPLER_STATE *sampler_state = GetSamplerState(sampler);
+    VK_OBJECT obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
     // Any bound cmd buffers are now invalid
-    if (sampler_state) InvalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
-    dev_data->samplerMap.erase(sampler);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    SAMPLER_STATE *sampler_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
-    if (!skip) {
-        if (sampler != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
+    if (sampler_state) {
+        InvalidateCommandBuffers(device_data, sampler_state->cb_bindings, obj_struct);
     }
+    device_data->samplerMap.erase(sampler);
 }
 
-static void PreCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
-    auto layout_it = dev_data->descriptorSetLayoutMap.find(ds_layout);
-    if (layout_it != dev_data->descriptorSetLayoutMap.end()) {
+void CoreChecks::PreCallRecordDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!descriptorSetLayout) return;
+    auto layout_it = device_data->descriptorSetLayoutMap.find(descriptorSetLayout);
+    if (layout_it != device_data->descriptorSetLayoutMap.end()) {
         layout_it->second.get()->MarkDestroyed();
-        dev_data->descriptorSetLayoutMap.erase(layout_it);
+        device_data->descriptorSetLayoutMap.erase(layout_it);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
+bool CoreChecks::PreCallValidateDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
                                                       const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    {
-        lock_guard_t lock(global_lock);
-        // Pre-record to avoid Destroy/Create race
-        PreCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
-    }
-    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
-}
-
-static bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
-                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
-    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
-    *obj_struct = {HandleToUint64(pool), kVulkanObjectTypeDescriptorPool};
-    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    DESCRIPTOR_POOL_STATE *desc_pool_state = GetDescriptorPoolState(descriptorPool);
+    VK_OBJECT obj_struct = {HandleToUint64(descriptorPool), kVulkanObjectTypeDescriptorPool};
+    if (device_data->instance_data->disabled.destroy_descriptor_pool) return false;
     bool skip = false;
-    if (*desc_pool_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, "vkDestroyDescriptorPool",
+    if (desc_pool_state) {
+        skip |= ValidateObjectNotInUse(device_data, desc_pool_state, obj_struct, "vkDestroyDescriptorPool",
                                        "VUID-vkDestroyDescriptorPool-descriptorPool-00303");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
-                                               DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
+void CoreChecks::PreCallRecordDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                    const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!descriptorPool) return;
+    DESCRIPTOR_POOL_STATE *desc_pool_state = GetDescriptorPoolState(descriptorPool);
+    VK_OBJECT obj_struct = {HandleToUint64(descriptorPool), kVulkanObjectTypeDescriptorPool};
     if (desc_pool_state) {
         // Any bound cmd buffers are now invalid
-        InvalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
+        InvalidateCommandBuffers(device_data, desc_pool_state->cb_bindings, obj_struct);
         // Free sets that were in this pool
         for (auto ds : desc_pool_state->sets) {
-            FreeDescriptorSet(dev_data, ds);
+            FreeDescriptorSet(device_data, ds);
         }
-        dev_data->descriptorPoolMap.erase(descriptorPool);
+        device_data->descriptorPoolMap.erase(descriptorPool);
         delete desc_pool_state;
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
-                                                 const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
-    if (!skip) {
-        // Pre-record to avoid Destroy/Create race
-        PreCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
-        lock.unlock();
-        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
-    }
-}
-
 // Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
 //  If this is a secondary command buffer, then make sure its primary is also in-flight
 //  If primary is not in-flight, then remove secondary from global in-flight set
 // This function is only valid at a point when cmdBuffer is being reset or freed
-static bool CheckCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
-                                       std::string error_code) {
+bool CoreChecks::CheckCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
+                                            const char *error_code) {
     bool skip = false;
     if (cb_node->in_use.load()) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                        HandleToUint64(cb_node->commandBuffer), error_code,
-                        "Attempt to %s command buffer (0x%" PRIx64 ") which is in use.", action,
-                        HandleToUint64(cb_node->commandBuffer));
+                        HandleToUint64(cb_node->commandBuffer), error_code, "Attempt to %s command buffer (%s) which is in use.",
+                        action, dev_data->report_data->FormatHandle(cb_node->commandBuffer).c_str());
     }
     return skip;
 }
 
 // Iterate over all cmdBuffers in given commandPool and verify that each is not in use
-static bool CheckCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
-                                        std::string error_code) {
+bool CoreChecks::CheckCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
+                                             const char *error_code) {
     bool skip = false;
     for (auto cmd_buffer : pPool->commandBuffers) {
-        skip |= CheckCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
+        skip |= CheckCommandBufferInFlight(dev_data, GetCBNode(cmd_buffer), action, error_code);
     }
     return skip;
 }
 
 // Free all command buffers in given list, removing all references/links to them using ResetCommandBufferState
-static void FreeCommandBufferStates(layer_data *dev_data, COMMAND_POOL_NODE *pool_state, const uint32_t command_buffer_count,
-                                    const VkCommandBuffer *command_buffers) {
+void CoreChecks::FreeCommandBufferStates(layer_data *dev_data, COMMAND_POOL_NODE *pool_state, const uint32_t command_buffer_count,
+                                         const VkCommandBuffer *command_buffers) {
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallRecordFreeCommandBuffers(dev_data, command_buffer_count, command_buffers);
+    }
     for (uint32_t i = 0; i < command_buffer_count; i++) {
-        auto cb_state = GetCBNode(dev_data, command_buffers[i]);
+        auto cb_state = GetCBNode(command_buffers[i]);
         // Remove references to command buffer's state and delete
         if (cb_state) {
             // reset prior to delete, removing various references to it.
@@ -4513,62 +4782,50 @@
     }
 }
 
-static bool PreCallValidateFreeCommandBuffers(layer_data *dev_data, uint32_t commandBufferCount,
-                                              const VkCommandBuffer *pCommandBuffers) {
+bool CoreChecks::PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                   const VkCommandBuffer *pCommandBuffers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
     for (uint32_t i = 0; i < commandBufferCount; i++) {
-        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
+        auto cb_node = GetCBNode(pCommandBuffers[i]);
         // Delete CB information structure, and remove from commandBufferMap
         if (cb_node) {
-            skip |= CheckCommandBufferInFlight(dev_data, cb_node, "free", "VUID-vkFreeCommandBuffers-pCommandBuffers-00047");
+            skip |= CheckCommandBufferInFlight(device_data, cb_node, "free", "VUID-vkFreeCommandBuffers-pCommandBuffers-00047");
         }
     }
     return skip;
 }
 
-static void PreCallRecordFreeCommandBuffers(layer_data *dev_data, VkCommandPool commandPool, uint32_t commandBufferCount,
-                                            const VkCommandBuffer *pCommandBuffers) {
-    auto pPool = GetCommandPoolNode(dev_data, commandPool);
-    FreeCommandBufferStates(dev_data, pPool, commandBufferCount, pCommandBuffers);
+void CoreChecks::PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                 const VkCommandBuffer *pCommandBuffers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto pPool = GetCommandPoolNode(commandPool);
+    FreeCommandBufferStates(device_data, pPool, commandBufferCount, pCommandBuffers);
 }
 
-VKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
-                                              const VkCommandBuffer *pCommandBuffers) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateFreeCommandBuffers(dev_data, commandBufferCount, pCommandBuffers);
-    if (skip) return;
-    PreCallRecordFreeCommandBuffers(dev_data, commandPool, commandBufferCount, pCommandBuffers);
-    lock.unlock();
-
-    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
+bool CoreChecks::PreCallValidateCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateDeviceQueueFamily(device_data, pCreateInfo->queueFamilyIndex, "vkCreateCommandPool",
+                                     "pCreateInfo->queueFamilyIndex", "VUID-vkCreateCommandPool-queueFamilyIndex-01937");
 }
 
-static void PostCallRecordCreateCommandPool(layer_data *dev_data, const VkCommandPoolCreateInfo *pCreateInfo,
-                                            VkCommandPool *pCommandPool) {
-    dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
-    dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
+void CoreChecks::PostCallRecordCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
+                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool,
+                                                 VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    device_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
+    device_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
-                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
-
-    if (VK_SUCCESS == result) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateCommandPool(dev_data, pCreateInfo, pCommandPool);
-    }
-    return result;
-}
-
-static bool PreCallValidateCreateQueryPool(layer_data *dev_data, const VkQueryPoolCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
     if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
-        if (!dev_data->enabled_features.core.pipelineStatisticsQuery) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
+        if (!device_data->enabled_features.core.pipelineStatisticsQuery) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
                             "VUID-VkQueryPoolCreateInfo-queryType-00791",
                             "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device with "
                             "VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE.");
@@ -4577,112 +4834,79 @@
     return skip;
 }
 
-static void PostCallRecordCreateQueryPool(layer_data *dev_data, const VkQueryPoolCreateInfo *pCreateInfo, VkQueryPool *pQueryPool) {
-    QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
+void CoreChecks::PostCallRecordCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    QUERY_POOL_NODE *qp_node = &device_data->queryPoolMap[*pQueryPool];
     qp_node->createInfo = *pCreateInfo;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
-                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateQueryPool(dev_data, pCreateInfo);
-    lock.unlock();
+bool CoreChecks::PreCallValidateDestroyCommandPool(VkDevice device, VkCommandPool commandPool,
+                                                   const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
 
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    if (!skip) {
-        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
-    }
-    if (result == VK_SUCCESS) {
-        lock.lock();
-        PostCallRecordCreateQueryPool(dev_data, pCreateInfo, pQueryPool);
-    }
-    return result;
-}
-
-static bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool) {
-    COMMAND_POOL_NODE *cp_state = GetCommandPoolNode(dev_data, pool);
-    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
+    COMMAND_POOL_NODE *cp_state = GetCommandPoolNode(commandPool);
+    if (device_data->instance_data->disabled.destroy_command_pool) return false;
     bool skip = false;
     if (cp_state) {
         // Verify that command buffers in pool are complete (not in-flight)
-        skip |= CheckCommandBuffersInFlight(dev_data, cp_state, "destroy command pool with",
+        skip |= CheckCommandBuffersInFlight(device_data, cp_state, "destroy command pool with",
                                             "VUID-vkDestroyCommandPool-commandPool-00041");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool) {
-    COMMAND_POOL_NODE *cp_state = GetCommandPoolNode(dev_data, pool);
+void CoreChecks::PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool,
+                                                 const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!commandPool) return;
+    COMMAND_POOL_NODE *cp_state = GetCommandPoolNode(commandPool);
     // Remove cmdpool from cmdpoolmap, after freeing layer data for the command buffers
     // "When a pool is destroyed, all command buffers allocated from the pool are freed."
     if (cp_state) {
         // Create a vector, as FreeCommandBufferStates deletes from cp_state->commandBuffers during iteration.
         std::vector<VkCommandBuffer> cb_vec{cp_state->commandBuffers.begin(), cp_state->commandBuffers.end()};
-        FreeCommandBufferStates(dev_data, cp_state, static_cast<uint32_t>(cb_vec.size()), cb_vec.data());
-        dev_data->commandPoolMap.erase(pool);
+        FreeCommandBufferStates(device_data, cp_state, static_cast<uint32_t>(cb_vec.size()), cb_vec.data());
+        device_data->commandPoolMap.erase(commandPool);
     }
 }
 
-// Destroy commandPool along with all of the commandBuffers allocated from that pool
-VKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool);
-    if (!skip) {
-        // Pre-record to avoid Destroy/Create race
-        PreCallRecordDestroyCommandPool(dev_data, commandPool);
-        lock.unlock();
-        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
-    }
+bool CoreChecks::PreCallValidateResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto command_pool_state = GetCommandPoolNode(commandPool);
+    return CheckCommandBuffersInFlight(device_data, command_pool_state, "reset command pool with",
+                                       "VUID-vkResetCommandPool-commandPool-00040");
 }
 
-static bool PreCallValidateResetCommandPool(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
-    return CheckCommandBuffersInFlight(dev_data, pPool, "reset command pool with", "VUID-vkResetCommandPool-commandPool-00040");
-}
-
-static void PostCallRecordResetCommandPool(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
-    for (auto cmdBuffer : pPool->commandBuffers) {
-        ResetCommandBufferState(dev_data, cmdBuffer);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto pPool = GetCommandPoolNode(dev_data, commandPool);
-    bool skip = PreCallValidateResetCommandPool(dev_data, pPool);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
-
+void CoreChecks::PostCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags,
+                                                VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
     // Reset all of the CBs allocated from this pool
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordResetCommandPool(dev_data, pPool);
-        lock.unlock();
+    auto command_pool_state = GetCommandPoolNode(commandPool);
+    for (auto cmdBuffer : command_pool_state->commandBuffers) {
+        ResetCommandBufferState(device_data, cmdBuffer);
     }
-    return result;
 }
 
-static bool PreCallValidateResetFences(layer_data *dev_data, uint32_t fenceCount, const VkFence *pFences) {
+bool CoreChecks::PreCallValidateResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
     for (uint32_t i = 0; i < fenceCount; ++i) {
-        auto pFence = GetFenceNode(dev_data, pFences[i]);
+        auto pFence = GetFenceNode(pFences[i]);
         if (pFence && pFence->scope == kSyncScopeInternal && pFence->state == FENCE_INFLIGHT) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
-                            HandleToUint64(pFences[i]), "VUID-vkResetFences-pFences-01123", "Fence 0x%" PRIx64 " is in use.",
-                            HandleToUint64(pFences[i]));
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+                            HandleToUint64(pFences[i]), "VUID-vkResetFences-pFences-01123", "Fence %s is in use.",
+                            device_data->report_data->FormatHandle(pFences[i]).c_str());
         }
     }
     return skip;
 }
 
-static void PostCallRecordResetFences(layer_data *dev_data, uint32_t fenceCount, const VkFence *pFences) {
+void CoreChecks::PostCallRecordResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkResult result) {
     for (uint32_t i = 0; i < fenceCount; ++i) {
-        auto pFence = GetFenceNode(dev_data, pFences[i]);
+        auto pFence = GetFenceNode(pFences[i]);
         if (pFence) {
             if (pFence->scope == kSyncScopeInternal) {
                 pFence->state = FENCE_UNSIGNALED;
@@ -4693,33 +4917,15 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateResetFences(dev_data, fenceCount, pFences);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
-
-    if (result == VK_SUCCESS) {
-        lock.lock();
-        PostCallRecordResetFences(dev_data, fenceCount, pFences);
-        lock.unlock();
-    }
-
-    return result;
-}
-
 // For given cb_nodes, invalidate them and track object causing invalidation
-void InvalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
+void CoreChecks::InvalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes,
+                                          VK_OBJECT obj) {
     for (auto cb_node : cb_nodes) {
         if (cb_node->state == CB_RECORDING) {
             log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidCommandBuffer,
-                    "Invalidating a command buffer that's currently being recorded: 0x%" PRIx64 ".",
-                    HandleToUint64(cb_node->commandBuffer));
+                    "Invalidating a command buffer that's currently being recorded: %s.",
+                    dev_data->report_data->FormatHandle(cb_node->commandBuffer).c_str());
             cb_node->state = CB_INVALID_INCOMPLETE;
         } else if (cb_node->state == CB_RECORDED) {
             cb_node->state = CB_INVALID_COMPLETE;
@@ -4733,295 +4939,120 @@
     }
 }
 
-static bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
-                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
-    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
-    *obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
-    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
+bool CoreChecks::PreCallValidateDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer,
+                                                   const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    FRAMEBUFFER_STATE *framebuffer_state = GetFramebufferState(framebuffer);
+    VK_OBJECT obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
     bool skip = false;
-    if (*framebuffer_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, "vkDestroyFramebuffer",
+    if (framebuffer_state) {
+        skip |= ValidateObjectNotInUse(device_data, framebuffer_state, obj_struct, "vkDestroyFramebuffer",
                                        "VUID-vkDestroyFramebuffer-framebuffer-00892");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
-                                            VK_OBJECT obj_struct) {
-    InvalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
-    dev_data->frameBufferMap.erase(framebuffer);
+void CoreChecks::PreCallRecordDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer,
+                                                 const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!framebuffer) return;
+    FRAMEBUFFER_STATE *framebuffer_state = GetFramebufferState(framebuffer);
+    VK_OBJECT obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
+    InvalidateCommandBuffers(device_data, framebuffer_state->cb_bindings, obj_struct);
+    device_data->frameBufferMap.erase(framebuffer);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
-    if (!skip) {
-        if (framebuffer != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
-    }
-}
-
-static bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
-                                             VK_OBJECT *obj_struct) {
-    *rp_state = GetRenderPassState(dev_data, render_pass);
-    *obj_struct = {HandleToUint64(render_pass), kVulkanObjectTypeRenderPass};
-    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
+bool CoreChecks::PreCallValidateDestroyRenderPass(VkDevice device, VkRenderPass renderPass,
+                                                  const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RENDER_PASS_STATE *rp_state = GetRenderPassState(renderPass);
+    VK_OBJECT obj_struct = {HandleToUint64(renderPass), kVulkanObjectTypeRenderPass};
     bool skip = false;
-    if (*rp_state) {
-        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, "vkDestroyRenderPass",
+    if (rp_state) {
+        skip |= ValidateObjectNotInUse(device_data, rp_state, obj_struct, "vkDestroyRenderPass",
                                        "VUID-vkDestroyRenderPass-renderPass-00873");
     }
     return skip;
 }
 
-static void PreCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
-                                           VK_OBJECT obj_struct) {
-    InvalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
-    dev_data->renderPassMap.erase(render_pass);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    RENDER_PASS_STATE *rp_state = nullptr;
-    VK_OBJECT obj_struct;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
-    if (!skip) {
-        if (renderPass != VK_NULL_HANDLE) {
-            // Pre-record to avoid Destroy/Create race
-            PreCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
-        }
-        lock.unlock();
-        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
-                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
-        lock.unlock();
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
-                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
-        lock.unlock();
-    }
-    return result;
+void CoreChecks::PreCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!renderPass) return;
+    RENDER_PASS_STATE *rp_state = GetRenderPassState(renderPass);
+    VK_OBJECT obj_struct = {HandleToUint64(renderPass), kVulkanObjectTypeRenderPass};
+    InvalidateCommandBuffers(device_data, rp_state->cb_bindings, obj_struct);
+    device_data->renderPassMap.erase(renderPass);
 }
 
 // Access helper functions for external modules
-VkFormatProperties GetFormatProperties(const core_validation::layer_data *device_data, const VkFormat format) {
+VkFormatProperties CoreChecks::GetPDFormatProperties(const VkFormat format) {
     VkFormatProperties format_properties;
-    instance_layer_data *instance_data =
-        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
-    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &format_properties);
+    instance_dispatch_table.GetPhysicalDeviceFormatProperties(physical_device, format, &format_properties);
     return format_properties;
 }
 
-VkResult GetImageFormatProperties(core_validation::layer_data *device_data, const VkImageCreateInfo *image_ci,
-                                  VkImageFormatProperties *pImageFormatProperties) {
-    instance_layer_data *instance_data =
-        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
-    return instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(
-        device_data->physical_device, image_ci->format, image_ci->imageType, image_ci->tiling, image_ci->usage, image_ci->flags,
-        pImageFormatProperties);
+VkResult CoreChecks::GetPDImageFormatProperties(const VkImageCreateInfo *image_ci,
+                                                VkImageFormatProperties *pImageFormatProperties) {
+    return instance_dispatch_table.GetPhysicalDeviceImageFormatProperties(physical_device, image_ci->format, image_ci->imageType,
+                                                                          image_ci->tiling, image_ci->usage, image_ci->flags,
+                                                                          pImageFormatProperties);
 }
 
-const debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
-
-const VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(const core_validation::layer_data *device_data) {
-    return &device_data->phys_dev_props;
+VkResult CoreChecks::GetPDImageFormatProperties2(const VkPhysicalDeviceImageFormatInfo2 *phys_dev_image_fmt_info,
+                                                 VkImageFormatProperties2 *pImageFormatProperties) {
+    if (!instance_extensions.vk_khr_get_physical_device_properties_2) return VK_ERROR_EXTENSION_NOT_PRESENT;
+    return instance_dispatch_table.GetPhysicalDeviceImageFormatProperties2(physical_device, phys_dev_image_fmt_info,
+                                                                           pImageFormatProperties);
 }
 
-const CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
+const debug_report_data *CoreChecks::GetReportData() { return report_data; }
 
-std::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
-    return &device_data->imageMap;
+const VkLayerDispatchTable *CoreChecks::GetDispatchTable() { return &device_dispatch_table; }
+
+const VkPhysicalDeviceProperties *CoreChecks::GetPDProperties() { return &phys_dev_props; }
+
+const VkPhysicalDeviceMemoryProperties *CoreChecks::GetPhysicalDeviceMemoryProperties() { return &phys_dev_mem_props; }
+
+const CHECK_DISABLED *CoreChecks::GetDisables() { return &instance_state->disabled; }
+
+const CHECK_ENABLED *CoreChecks::GetEnables() { return &instance_state->enabled; }
+
+std::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *CoreChecks::GetImageMap() { return &imageMap; }
+
+std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *CoreChecks::GetImageSubresourceMap() {
+    return &imageSubresourceMap;
 }
 
-std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
-    return &device_data->imageSubresourceMap;
-}
+std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *CoreChecks::GetImageLayoutMap() { return &imageLayoutMap; }
 
-std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
-    return &device_data->imageLayoutMap;
-}
+std::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *CoreChecks::GetBufferMap() { return &bufferMap; }
 
-std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *device_data) {
-    return &device_data->imageLayoutMap;
-}
+std::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *CoreChecks::GetBufferViewMap() { return &bufferViewMap; }
 
-std::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
-    return &device_data->bufferMap;
-}
+std::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *CoreChecks::GetImageViewMap() { return &imageViewMap; }
 
-std::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
-    return &device_data->bufferViewMap;
-}
+const DeviceFeatures *CoreChecks::GetEnabledFeatures() { return &enabled_features; }
 
-std::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
-    return &device_data->imageViewMap;
-}
+const DeviceExtensions *CoreChecks::GetDeviceExtensions() { return &device_extensions; }
 
-const PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) { return &device_data->phys_dev_properties; }
+GpuValidationState *CoreChecks::GetGpuValidationState() { return &gpu_validation_state; }
 
-const DeviceFeatures *GetEnabledFeatures(const layer_data *device_data) { return &device_data->enabled_features; }
+VkDevice CoreChecks::GetDevice() { return device; }
 
-const DeviceExtensions *GetDeviceExtensions(const layer_data *device_data) { return &device_data->extensions; }
+uint32_t CoreChecks::GetApiVersion() { return api_version; }
 
-uint32_t GetApiVersion(const layer_data *device_data) { return device_data->api_version; }
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
-                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
-    if (!skip) {
-        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
-    }
-    if (VK_SUCCESS == result) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
-                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
-        lock.unlock();
-    }
-
-    return result;
-}
-
-static void PostCallRecordCreateFence(layer_data *dev_data, const VkFenceCreateInfo *pCreateInfo, VkFence *pFence) {
-    auto &fence_node = dev_data->fenceMap[*pFence];
+void CoreChecks::PostCallRecordCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    auto &fence_node = device_data->fenceMap[*pFence];
     fence_node.fence = *pFence;
     fence_node.createInfo = *pCreateInfo;
     fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
-                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
-    if (VK_SUCCESS == result) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateFence(dev_data, pCreateInfo, pFence);
-    }
-    return result;
-}
-
-// TODO handle pipeline caches
-VKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
-                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
-                                                const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Pre-record to avoid Destroy/Create race (if/when implemented)
-    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
-                                                    void *pData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
-                                                   const VkPipelineCache *pSrcCaches) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
-    return result;
-}
-
 // Validation cache:
 // CV is the bottommost implementor of this extension. Don't pass calls down.
-VKAPI_ATTR VkResult VKAPI_CALL CreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo,
-                                                        const VkAllocationCallbacks *pAllocator,
-                                                        VkValidationCacheEXT *pValidationCache) {
-    *pValidationCache = ValidationCache::Create(pCreateInfo);
-    return *pValidationCache ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache,
-                                                     const VkAllocationCallbacks *pAllocator) {
-    delete (ValidationCache *)validationCache;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize,
-                                                         void *pData) {
-    size_t inSize = *pDataSize;
-    ((ValidationCache *)validationCache)->Write(pDataSize, pData);
-    return (pData && *pDataSize != inSize) ? VK_INCOMPLETE : VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL MergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount,
-                                                        const VkValidationCacheEXT *pSrcCaches) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = false;
-    auto dst = (ValidationCache *)dstCache;
-    auto src = (ValidationCache const *const *)pSrcCaches;
-    VkResult result = VK_SUCCESS;
-    for (uint32_t i = 0; i < srcCacheCount; i++) {
-        if (src[i] == dst) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT,
-                            0, "VUID-vkMergeValidationCachesEXT-dstCache-01536",
-                            "vkMergeValidationCachesEXT: dstCache (0x%" PRIx64 ") must not appear in pSrcCaches array.",
-                            HandleToUint64(dstCache));
-            result = VK_ERROR_VALIDATION_FAILED_EXT;
-        }
-        if (!skip) {
-            dst->Merge(src[i]);
-        }
-    }
-
-    return result;
-}
-
 // utility function to set collective state for pipeline
 void SetPipelineState(PIPELINE_STATE *pPipe) {
     // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
@@ -5043,228 +5074,255 @@
     }
 }
 
-static bool PreCallValidateCreateGraphicsPipelines(layer_data *dev_data, vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state,
-                                                   const uint32_t count, const VkGraphicsPipelineCreateInfo *pCreateInfos) {
+bool CoreChecks::ValidatePipelineVertexDivisors(layer_data *dev_data,
+                                                std::vector<std::unique_ptr<PIPELINE_STATE>> const &pipe_state_vec,
+                                                const uint32_t count, const VkGraphicsPipelineCreateInfo *pipe_cis) {
     bool skip = false;
-    pipe_state->reserve(count);
-    // TODO - State changes and validation need to be untangled here
+    const VkPhysicalDeviceLimits *device_limits = &(GetPDProperties()->limits);
+
     for (uint32_t i = 0; i < count; i++) {
-        pipe_state->push_back(std::unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
-        (*pipe_state)[i]->initGraphicsPipeline(&pCreateInfos[i], GetRenderPassStateSharedPtr(dev_data, pCreateInfos[i].renderPass));
-        (*pipe_state)[i]->pipeline_layout = *GetPipelineLayout(dev_data, pCreateInfos[i].layout);
+        auto pvids_ci = lvl_find_in_chain<VkPipelineVertexInputDivisorStateCreateInfoEXT>(pipe_cis[i].pVertexInputState->pNext);
+        if (nullptr == pvids_ci) continue;
+
+        const PIPELINE_STATE *pipe_state = pipe_state_vec[i].get();
+        for (uint32_t j = 0; j < pvids_ci->vertexBindingDivisorCount; j++) {
+            const VkVertexInputBindingDivisorDescriptionEXT *vibdd = &(pvids_ci->pVertexBindingDivisors[j]);
+            if (vibdd->binding >= device_limits->maxVertexInputBindings) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                    HandleToUint64(pipe_state->pipeline), "VUID-VkVertexInputBindingDivisorDescriptionEXT-binding-01869",
+                    "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
+                    "pVertexBindingDivisors[%1u] binding index of (%1u) exceeds device maxVertexInputBindings (%1u).",
+                    i, j, vibdd->binding, device_limits->maxVertexInputBindings);
+            }
+            if (vibdd->divisor > dev_data->phys_dev_ext_props.vtx_attrib_divisor_props.maxVertexAttribDivisor) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                    HandleToUint64(pipe_state->pipeline), "VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870",
+                    "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
+                    "pVertexBindingDivisors[%1u] divisor of (%1u) exceeds extension maxVertexAttribDivisor (%1u).",
+                    i, j, vibdd->divisor, dev_data->phys_dev_ext_props.vtx_attrib_divisor_props.maxVertexAttribDivisor);
+            }
+            if ((0 == vibdd->divisor) &&
+                !dev_data->enabled_features.vtx_attrib_divisor_features.vertexAttributeInstanceRateZeroDivisor) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                    HandleToUint64(pipe_state->pipeline),
+                    "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228",
+                    "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
+                    "pVertexBindingDivisors[%1u] divisor must not be 0 when vertexAttributeInstanceRateZeroDivisor feature is not "
+                    "enabled.",
+                    i, j);
+            }
+            if ((1 != vibdd->divisor) &&
+                !dev_data->enabled_features.vtx_attrib_divisor_features.vertexAttributeInstanceRateDivisor) {
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                    HandleToUint64(pipe_state->pipeline),
+                    "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229",
+                    "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
+                    "pVertexBindingDivisors[%1u] divisor (%1u) must be 1 when vertexAttributeInstanceRateDivisor feature is not "
+                    "enabled.",
+                    i, j, vibdd->divisor);
+            }
+
+            // Find the corresponding binding description and validate input rate setting
+            bool failed_01871 = true;
+            for (size_t k = 0; k < pipe_state->vertex_binding_descriptions_.size(); k++) {
+                if ((vibdd->binding == pipe_state->vertex_binding_descriptions_[k].binding) &&
+                    (VK_VERTEX_INPUT_RATE_INSTANCE == pipe_state->vertex_binding_descriptions_[k].inputRate)) {
+                    failed_01871 = false;
+                    break;
+                }
+            }
+            if (failed_01871) {  // Description not found, or has incorrect inputRate value
+                skip |= log_msg(
+                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                    HandleToUint64(pipe_state->pipeline), "VUID-VkVertexInputBindingDivisorDescriptionEXT-inputRate-01871",
+                    "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
+                    "pVertexBindingDivisors[%1u] specifies binding index (%1u), but that binding index's "
+                    "VkVertexInputBindingDescription.inputRate member is not VK_VERTEX_INPUT_RATE_INSTANCE.",
+                    i, j, vibdd->binding);
+            }
+        }
+    }
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                        const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                        const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                        void *cgpl_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    bool skip = false;
+    create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
+    cgpl_state->pipe_state.reserve(count);
+    for (uint32_t i = 0; i < count; i++) {
+        cgpl_state->pipe_state.push_back(std::unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
+        (cgpl_state->pipe_state)[i]->initGraphicsPipeline(&pCreateInfos[i],
+                                                          GetRenderPassStateSharedPtr(pCreateInfos[i].renderPass));
+        (cgpl_state->pipe_state)[i]->pipeline_layout = *GetPipelineLayout(device_data, pCreateInfos[i].layout);
     }
 
     for (uint32_t i = 0; i < count; i++) {
-        skip |= ValidatePipelineLocked(dev_data, *pipe_state, i);
+        skip |= ValidatePipelineLocked(device_data, cgpl_state->pipe_state, i);
     }
 
     for (uint32_t i = 0; i < count; i++) {
-        skip |= ValidatePipelineUnlocked(dev_data, *pipe_state, i);
+        skip |= ValidatePipelineUnlocked(device_data, cgpl_state->pipe_state, i);
+    }
+
+    if (device_data->device_extensions.vk_ext_vertex_attribute_divisor) {
+        skip |= ValidatePipelineVertexDivisors(device_data, cgpl_state->pipe_state, count, pCreateInfos);
     }
 
     return skip;
 }
 
-static void PostCallRecordCreateGraphicsPipelines(layer_data *dev_data, vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state,
-                                                  const uint32_t count, VkPipeline *pPipelines) {
+// GPU validation may replace pCreateInfos for the down-chain call
+void CoreChecks::PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                      const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                      void *cgpl_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
+    cgpl_state->pCreateInfos = pCreateInfos;
+    // GPU Validation may replace instrumented shaders with non-instrumented ones, so allow it to modify the createinfos.
+    if (GetEnables()->gpu_validation) {
+        cgpl_state->gpu_create_infos = GpuPreCallRecordCreateGraphicsPipelines(device_data, pipelineCache, count, pCreateInfos,
+                                                                               pAllocator, pPipelines, cgpl_state->pipe_state);
+        cgpl_state->pCreateInfos = reinterpret_cast<VkGraphicsPipelineCreateInfo *>(cgpl_state->gpu_create_infos.data());
+    }
+}
+
+void CoreChecks::PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                       VkResult result, void *cgpl_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
+    // This API may create pipelines regardless of the return value
     for (uint32_t i = 0; i < count; i++) {
         if (pPipelines[i] != VK_NULL_HANDLE) {
-            (*pipe_state)[i]->pipeline = pPipelines[i];
-            dev_data->pipelineMap[pPipelines[i]] = std::move((*pipe_state)[i]);
+            (cgpl_state->pipe_state)[i]->pipeline = pPipelines[i];
+            device_data->pipelineMap[pPipelines[i]] = std::move((cgpl_state->pipe_state)[i]);
         }
     }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
-                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
-                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    // The order of operations here is a little convoluted but gets the job done
-    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
-    //  2. Create state is then validated (which uses flags setup during shadowing)
-    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
-    vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateCreateGraphicsPipelines(dev_data, &pipe_state, count, pCreateInfos);
-
-    if (skip) {
-        for (uint32_t i = 0; i < count; i++) {
-            pPipelines[i] = VK_NULL_HANDLE;
-        }
-        return VK_ERROR_VALIDATION_FAILED_EXT;
+    // GPU val needs clean up regardless of result
+    if (GetEnables()->gpu_validation) {
+        GpuPostCallRecordCreateGraphicsPipelines(device_data, count, pCreateInfos, pAllocator, pPipelines);
+        cgpl_state->gpu_create_infos.clear();
     }
-    lock.unlock();
-
-    auto result =
-        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
-
-    lock.lock();
-    PostCallRecordCreateGraphicsPipelines(dev_data, &pipe_state, count, pPipelines);
-
-    return result;
+    cgpl_state->pipe_state.clear();
 }
 
-static bool PreCallValidateCreateComputePipelines(layer_data *dev_data, vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state,
-                                                  const uint32_t count, const VkComputePipelineCreateInfo *pCreateInfos) {
+bool CoreChecks::PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                       const VkComputePipelineCreateInfo *pCreateInfos,
+                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                       void *pipe_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
+    std::vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state =
+        reinterpret_cast<std::vector<std::unique_ptr<PIPELINE_STATE>> *>(pipe_state_data);
     pipe_state->reserve(count);
     for (uint32_t i = 0; i < count; i++) {
         // Create and initialize internal tracking data structure
         pipe_state->push_back(unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
         (*pipe_state)[i]->initComputePipeline(&pCreateInfos[i]);
-        (*pipe_state)[i]->pipeline_layout = *GetPipelineLayout(dev_data, pCreateInfos[i].layout);
+        (*pipe_state)[i]->pipeline_layout = *GetPipelineLayout(device_data, pCreateInfos[i].layout);
 
         // TODO: Add Compute Pipeline Verification
-        skip |= ValidateComputePipeline(dev_data, (*pipe_state)[i].get());
+        skip |= ValidateComputePipeline(device_data, (*pipe_state)[i].get());
     }
     return skip;
 }
 
-static void PostCallRecordCreateComputePipelines(layer_data *dev_data, vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state,
-                                                 const uint32_t count, VkPipeline *pPipelines) {
+void CoreChecks::PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                      const VkComputePipelineCreateInfo *pCreateInfos,
+                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                      VkResult result, void *pipe_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    std::vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state =
+        reinterpret_cast<std::vector<std::unique_ptr<PIPELINE_STATE>> *>(pipe_state_data);
+
+    // This API may create pipelines regardless of the return value
     for (uint32_t i = 0; i < count; i++) {
         if (pPipelines[i] != VK_NULL_HANDLE) {
             (*pipe_state)[i]->pipeline = pPipelines[i];
-            dev_data->pipelineMap[pPipelines[i]] = std::move((*pipe_state)[i]);
+            device_data->pipelineMap[pPipelines[i]] = std::move((*pipe_state)[i]);
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
-                                                      const VkComputePipelineCreateInfo *pCreateInfos,
-                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateComputePipelines(dev_data, &pipe_state, count, pCreateInfos);
-    if (skip) {
-        for (uint32_t i = 0; i < count; i++) {
-            pPipelines[i] = VK_NULL_HANDLE;
-        }
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    lock.unlock();
-
-    auto result =
-        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
-
-    lock.lock();
-    PostCallRecordCreateComputePipelines(dev_data, &pipe_state, count, pPipelines);
-
-    return result;
-}
-
-static bool PreCallValidateCreateRaytracingPipelinesNVX(layer_data *dev_data, uint32_t count,
-                                                        const VkRaytracingPipelineCreateInfoNVX *pCreateInfos,
-                                                        vector<std::unique_ptr<PIPELINE_STATE>> &pipe_state) {
+bool CoreChecks::PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                            const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
+                                                            const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                            void *pipe_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-
     // The order of operations here is a little convoluted but gets the job done
     //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
     //  2. Create state is then validated (which uses flags setup during shadowing)
     //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
     uint32_t i = 0;
+    vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state =
+        reinterpret_cast<vector<std::unique_ptr<PIPELINE_STATE>> *>(pipe_state_data);
+    pipe_state->reserve(count);
     for (i = 0; i < count; i++) {
-        pipe_state.push_back(std::unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
-        pipe_state[i]->initRaytracingPipelineNVX(&pCreateInfos[i]);
-        pipe_state[i]->pipeline_layout = *GetPipelineLayout(dev_data, pCreateInfos[i].layout);
+        pipe_state->push_back(std::unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
+        (*pipe_state)[i]->initRayTracingPipelineNV(&pCreateInfos[i]);
+        (*pipe_state)[i]->pipeline_layout = *GetPipelineLayout(device_data, pCreateInfos[i].layout);
     }
 
     for (i = 0; i < count; i++) {
-        skip |= ValidateRaytracingPipelineNVX(dev_data, pipe_state[i].get());
+        skip |= ValidateRayTracingPipelineNV(device_data, (*pipe_state)[i].get());
     }
 
     return skip;
 }
 
-static void PostCallRecordCreateRaytracingPipelinesNVX(layer_data *dev_data, uint32_t count,
-                                                       vector<std::unique_ptr<PIPELINE_STATE>> &pipe_state,
-                                                       VkPipeline *pPipelines) {
+void CoreChecks::PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                           const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
+                                                           const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
+                                                           VkResult result, void *pipe_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    vector<std::unique_ptr<PIPELINE_STATE>> *pipe_state =
+        reinterpret_cast<vector<std::unique_ptr<PIPELINE_STATE>> *>(pipe_state_data);
+    // This API may create pipelines regardless of the return value
     for (uint32_t i = 0; i < count; i++) {
         if (pPipelines[i] != VK_NULL_HANDLE) {
-            pipe_state[i]->pipeline = pPipelines[i];
-            dev_data->pipelineMap[pPipelines[i]] = std::move(pipe_state[i]);
+            (*pipe_state)[i]->pipeline = pPipelines[i];
+            device_data->pipelineMap[pPipelines[i]] = std::move((*pipe_state)[i]);
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateRaytracingPipelinesNVX(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
-                                                            const VkRaytracingPipelineCreateInfoNVX *pCreateInfos,
-                                                            const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    bool skip = false;
-    vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
-    pipe_state.reserve(count);
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-
-    skip |= PreCallValidateCreateRaytracingPipelinesNVX(dev_data, count, pCreateInfos, pipe_state);
-
-    lock.unlock();
-
-    if (skip) {
-        for (uint32_t i = 0; i < count; i++) {
-            pPipelines[i] = VK_NULL_HANDLE;
-        }
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-
-    auto result =
-        dev_data->dispatch_table.CreateRaytracingPipelinesNVX(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
-    lock.lock();
-
-    PostCallRecordCreateRaytracingPipelinesNVX(dev_data, count, pipe_state, pPipelines);
-
-    return result;
+void CoreChecks::PostCallRecordCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
+                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    device_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
 }
 
-static void PostCallRecordCreateSampler(layer_data *dev_data, const VkSamplerCreateInfo *pCreateInfo, VkSampler *pSampler) {
-    dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
-                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
-    if (VK_SUCCESS == result) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateSampler(dev_data, pCreateInfo, pSampler);
-    }
-    return result;
-}
-
-static bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
-    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
+bool CoreChecks::PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                          const VkAllocationCallbacks *pAllocator,
+                                                          VkDescriptorSetLayout *pSetLayout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (device_data->instance_data->disabled.create_descriptor_set_layout) return false;
     return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(
-        dev_data->report_data, create_info, dev_data->extensions.vk_khr_push_descriptor,
-        dev_data->phys_dev_ext_props.max_push_descriptors, dev_data->extensions.vk_ext_descriptor_indexing,
-        &dev_data->enabled_features.descriptor_indexing, &dev_data->enabled_features.inline_uniform_block,
-        &dev_data->phys_dev_ext_props.inline_uniform_block_props);
+        device_data->report_data, pCreateInfo, device_data->device_extensions.vk_khr_push_descriptor,
+        device_data->phys_dev_ext_props.max_push_descriptors, device_data->device_extensions.vk_ext_descriptor_indexing,
+        &device_data->enabled_features.descriptor_indexing, &device_data->enabled_features.inline_uniform_block,
+        &device_data->phys_dev_ext_props.inline_uniform_block_props);
 }
 
-static void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
-                                                    VkDescriptorSetLayout set_layout) {
-    dev_data->descriptorSetLayoutMap[set_layout] = std::make_shared<cvdescriptorset::DescriptorSetLayout>(create_info, set_layout);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
-                                                         const VkAllocationCallbacks *pAllocator,
-                                                         VkDescriptorSetLayout *pSetLayout) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
-    if (!skip) {
-        lock.unlock();
-        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
-        if (VK_SUCCESS == result) {
-            lock.lock();
-            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
-        }
-    }
-    return result;
+void CoreChecks::PostCallRecordCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                         const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout,
+                                                         VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    device_data->descriptorSetLayoutMap[*pSetLayout] =
+        std::make_shared<cvdescriptorset::DescriptorSetLayout>(pCreateInfo, *pSetLayout);
 }
 
 // Used by CreatePipelineLayout and CmdPushConstants.
@@ -5272,7 +5330,7 @@
 static bool ValidatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
                                       const char *caller_name, uint32_t index = 0) {
     if (dev_data->instance_data->disabled.push_constant_range) return false;
-    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
+    uint32_t const maxPushConstantsSize = dev_data->phys_dev_props.limits.maxPushConstantsSize;
     bool skip = false;
     // Check that offset + size don't exceed the max.
     // Prevent arithetic overflow here by avoiding addition and testing in this order.
@@ -5376,7 +5434,7 @@
     DSL_NUM_DESCRIPTOR_GROUPS
 };
 
-// Used by PreCallValiateCreatePipelineLayout.
+// Used by PreCallValidateCreatePipelineLayout.
 // Returns an array of size DSL_NUM_DESCRIPTOR_GROUPS of the maximum number of descriptors used in any single pipeline stage
 std::valarray<uint32_t> GetDescriptorCountMaxPerStage(
     const layer_data *dev_data, const std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> set_layouts,
@@ -5409,7 +5467,8 @@
 
             for (uint32_t binding_idx = 0; binding_idx < dsl->GetBindingCount(); binding_idx++) {
                 const VkDescriptorSetLayoutBinding *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
-                if (0 != (stage & binding->stageFlags)) {
+                // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
+                if (0 != (stage & binding->stageFlags) && binding->descriptorCount > 0) {
                     switch (binding->descriptorType) {
                         case VK_DESCRIPTOR_TYPE_SAMPLER:
                             stage_sum[DSL_TYPE_SAMPLERS] += binding->descriptorCount;
@@ -5468,35 +5527,40 @@
 
         for (uint32_t binding_idx = 0; binding_idx < dsl->GetBindingCount(); binding_idx++) {
             const VkDescriptorSetLayoutBinding *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
-            if (binding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
-                // count one block per binding. descriptorCount is number of bytes
-                sum_by_type[binding->descriptorType]++;
-            } else {
-                sum_by_type[binding->descriptorType] += binding->descriptorCount;
+            // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
+            if (binding->descriptorCount > 0) {
+                if (binding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+                    // count one block per binding. descriptorCount is number of bytes
+                    sum_by_type[binding->descriptorType]++;
+                } else {
+                    sum_by_type[binding->descriptorType] += binding->descriptorCount;
+                }
             }
         }
     }
     return sum_by_type;
 }
 
-static bool PreCallValiateCreatePipelineLayout(const layer_data *dev_data, const VkPipelineLayoutCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
 
     // Validate layout count against device physical limit
-    if (pCreateInfo->setLayoutCount > dev_data->phys_dev_props.limits.maxBoundDescriptorSets) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (pCreateInfo->setLayoutCount > device_data->phys_dev_props.limits.maxBoundDescriptorSets) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-setLayoutCount-00286",
                         "vkCreatePipelineLayout(): setLayoutCount (%d) exceeds physical device maxBoundDescriptorSets limit (%d).",
-                        pCreateInfo->setLayoutCount, dev_data->phys_dev_props.limits.maxBoundDescriptorSets);
+                        pCreateInfo->setLayoutCount, device_data->phys_dev_props.limits.maxBoundDescriptorSets);
     }
 
     // Validate Push Constant ranges
     uint32_t i, j;
     for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
-        skip |= ValidatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
+        skip |= ValidatePushConstantRange(device_data, pCreateInfo->pPushConstantRanges[i].offset,
                                           pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
         if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-VkPushConstantRange-stageFlags-requiredbitmask",
                             "vkCreatePipelineLayout() call has no stageFlags set.");
         }
@@ -5506,7 +5570,7 @@
     for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
         for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
             if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 "VUID-VkPipelineLayoutCreateInfo-pPushConstantRanges-00292",
                                 "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d.", i, j);
             }
@@ -5519,385 +5583,391 @@
     std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> set_layouts(pCreateInfo->setLayoutCount, nullptr);
     unsigned int push_descriptor_set_count = 0;
     {
-        unique_lock_t lock(global_lock);  // Lock while accessing global state
         for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
-            set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
+            set_layouts[i] = GetDescriptorSetLayout(device_data, pCreateInfo->pSetLayouts[i]);
             if (set_layouts[i]->IsPushDescriptor()) ++push_descriptor_set_count;
         }
-    }  // Unlock
+    }
 
     if (push_descriptor_set_count > 1) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00293",
                         "vkCreatePipelineLayout() Multiple push descriptor sets found.");
     }
 
     // Max descriptors by type, within a single pipeline stage
-    std::valarray<uint32_t> max_descriptors_per_stage = GetDescriptorCountMaxPerStage(dev_data, set_layouts, true);
+    std::valarray<uint32_t> max_descriptors_per_stage = GetDescriptorCountMaxPerStage(device_data, set_layouts, true);
     // Samplers
-    if (max_descriptors_per_stage[DSL_TYPE_SAMPLERS] > dev_data->phys_dev_props.limits.maxPerStageDescriptorSamplers) {
+    if (max_descriptors_per_stage[DSL_TYPE_SAMPLERS] > device_data->phys_dev_props.limits.maxPerStageDescriptorSamplers) {
         skip |=
-            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                     "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00287",
                     "vkCreatePipelineLayout(): max per-stage sampler bindings count (%d) exceeds device "
                     "maxPerStageDescriptorSamplers limit (%d).",
-                    max_descriptors_per_stage[DSL_TYPE_SAMPLERS], dev_data->phys_dev_props.limits.maxPerStageDescriptorSamplers);
+                    max_descriptors_per_stage[DSL_TYPE_SAMPLERS], device_data->phys_dev_props.limits.maxPerStageDescriptorSamplers);
     }
 
     // Uniform buffers
-    if (max_descriptors_per_stage[DSL_TYPE_UNIFORM_BUFFERS] > dev_data->phys_dev_props.limits.maxPerStageDescriptorUniformBuffers) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (max_descriptors_per_stage[DSL_TYPE_UNIFORM_BUFFERS] >
+        device_data->phys_dev_props.limits.maxPerStageDescriptorUniformBuffers) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00288",
                         "vkCreatePipelineLayout(): max per-stage uniform buffer bindings count (%d) exceeds device "
                         "maxPerStageDescriptorUniformBuffers limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_UNIFORM_BUFFERS],
-                        dev_data->phys_dev_props.limits.maxPerStageDescriptorUniformBuffers);
+                        device_data->phys_dev_props.limits.maxPerStageDescriptorUniformBuffers);
     }
 
     // Storage buffers
-    if (max_descriptors_per_stage[DSL_TYPE_STORAGE_BUFFERS] > dev_data->phys_dev_props.limits.maxPerStageDescriptorStorageBuffers) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (max_descriptors_per_stage[DSL_TYPE_STORAGE_BUFFERS] >
+        device_data->phys_dev_props.limits.maxPerStageDescriptorStorageBuffers) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00289",
                         "vkCreatePipelineLayout(): max per-stage storage buffer bindings count (%d) exceeds device "
                         "maxPerStageDescriptorStorageBuffers limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_STORAGE_BUFFERS],
-                        dev_data->phys_dev_props.limits.maxPerStageDescriptorStorageBuffers);
+                        device_data->phys_dev_props.limits.maxPerStageDescriptorStorageBuffers);
     }
 
     // Sampled images
-    if (max_descriptors_per_stage[DSL_TYPE_SAMPLED_IMAGES] > dev_data->phys_dev_props.limits.maxPerStageDescriptorSampledImages) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (max_descriptors_per_stage[DSL_TYPE_SAMPLED_IMAGES] >
+        device_data->phys_dev_props.limits.maxPerStageDescriptorSampledImages) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00290",
                         "vkCreatePipelineLayout(): max per-stage sampled image bindings count (%d) exceeds device "
                         "maxPerStageDescriptorSampledImages limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_SAMPLED_IMAGES],
-                        dev_data->phys_dev_props.limits.maxPerStageDescriptorSampledImages);
+                        device_data->phys_dev_props.limits.maxPerStageDescriptorSampledImages);
     }
 
     // Storage images
-    if (max_descriptors_per_stage[DSL_TYPE_STORAGE_IMAGES] > dev_data->phys_dev_props.limits.maxPerStageDescriptorStorageImages) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (max_descriptors_per_stage[DSL_TYPE_STORAGE_IMAGES] >
+        device_data->phys_dev_props.limits.maxPerStageDescriptorStorageImages) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00291",
                         "vkCreatePipelineLayout(): max per-stage storage image bindings count (%d) exceeds device "
                         "maxPerStageDescriptorStorageImages limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_STORAGE_IMAGES],
-                        dev_data->phys_dev_props.limits.maxPerStageDescriptorStorageImages);
+                        device_data->phys_dev_props.limits.maxPerStageDescriptorStorageImages);
     }
 
     // Input attachments
     if (max_descriptors_per_stage[DSL_TYPE_INPUT_ATTACHMENTS] >
-        dev_data->phys_dev_props.limits.maxPerStageDescriptorInputAttachments) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        device_data->phys_dev_props.limits.maxPerStageDescriptorInputAttachments) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01676",
                         "vkCreatePipelineLayout(): max per-stage input attachment bindings count (%d) exceeds device "
                         "maxPerStageDescriptorInputAttachments limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_INPUT_ATTACHMENTS],
-                        dev_data->phys_dev_props.limits.maxPerStageDescriptorInputAttachments);
+                        device_data->phys_dev_props.limits.maxPerStageDescriptorInputAttachments);
     }
 
     // Inline uniform blocks
     if (max_descriptors_per_stage[DSL_TYPE_INLINE_UNIFORM_BLOCK] >
-        dev_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        device_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-descriptorType-02214",
                         "vkCreatePipelineLayout(): max per-stage inline uniform block bindings count (%d) exceeds device "
                         "maxPerStageDescriptorInlineUniformBlocks limit (%d).",
                         max_descriptors_per_stage[DSL_TYPE_INLINE_UNIFORM_BLOCK],
-                        dev_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks);
+                        device_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks);
     }
 
     // Total descriptors by type
     //
-    std::map<uint32_t, uint32_t> sum_all_stages = GetDescriptorSum(dev_data, set_layouts, true);
+    std::map<uint32_t, uint32_t> sum_all_stages = GetDescriptorSum(device_data, set_layouts, true);
     // Samplers
     uint32_t sum = sum_all_stages[VK_DESCRIPTOR_TYPE_SAMPLER] + sum_all_stages[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER];
-    if (sum > dev_data->phys_dev_props.limits.maxDescriptorSetSamplers) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum > device_data->phys_dev_props.limits.maxDescriptorSetSamplers) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01677",
                         "vkCreatePipelineLayout(): sum of sampler bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetSamplers limit (%d).",
-                        sum, dev_data->phys_dev_props.limits.maxDescriptorSetSamplers);
+                        sum, device_data->phys_dev_props.limits.maxDescriptorSetSamplers);
     }
 
     // Uniform buffers
-    if (sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] > dev_data->phys_dev_props.limits.maxDescriptorSetUniformBuffers) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] > device_data->phys_dev_props.limits.maxDescriptorSetUniformBuffers) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01678",
                         "vkCreatePipelineLayout(): sum of uniform buffer bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetUniformBuffers limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER],
-                        dev_data->phys_dev_props.limits.maxDescriptorSetUniformBuffers);
+                        device_data->phys_dev_props.limits.maxDescriptorSetUniformBuffers);
     }
 
     // Dynamic uniform buffers
     if (sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] >
-        dev_data->phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        device_data->phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01679",
                         "vkCreatePipelineLayout(): sum of dynamic uniform buffer bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetUniformBuffersDynamic limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC],
-                        dev_data->phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic);
+                        device_data->phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic);
     }
 
     // Storage buffers
-    if (sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] > dev_data->phys_dev_props.limits.maxDescriptorSetStorageBuffers) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] > device_data->phys_dev_props.limits.maxDescriptorSetStorageBuffers) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01680",
                         "vkCreatePipelineLayout(): sum of storage buffer bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetStorageBuffers limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER],
-                        dev_data->phys_dev_props.limits.maxDescriptorSetStorageBuffers);
+                        device_data->phys_dev_props.limits.maxDescriptorSetStorageBuffers);
     }
 
     // Dynamic storage buffers
     if (sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] >
-        dev_data->phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        device_data->phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01681",
                         "vkCreatePipelineLayout(): sum of dynamic storage buffer bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetStorageBuffersDynamic limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC],
-                        dev_data->phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic);
+                        device_data->phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic);
     }
 
     //  Sampled images
     sum = sum_all_stages[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] + sum_all_stages[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] +
           sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER];
-    if (sum > dev_data->phys_dev_props.limits.maxDescriptorSetSampledImages) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum > device_data->phys_dev_props.limits.maxDescriptorSetSampledImages) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01682",
                         "vkCreatePipelineLayout(): sum of sampled image bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetSampledImages limit (%d).",
-                        sum, dev_data->phys_dev_props.limits.maxDescriptorSetSampledImages);
+                        sum, device_data->phys_dev_props.limits.maxDescriptorSetSampledImages);
     }
 
     //  Storage images
     sum = sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] + sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER];
-    if (sum > dev_data->phys_dev_props.limits.maxDescriptorSetStorageImages) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum > device_data->phys_dev_props.limits.maxDescriptorSetStorageImages) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01683",
                         "vkCreatePipelineLayout(): sum of storage image bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetStorageImages limit (%d).",
-                        sum, dev_data->phys_dev_props.limits.maxDescriptorSetStorageImages);
+                        sum, device_data->phys_dev_props.limits.maxDescriptorSetStorageImages);
     }
 
     // Input attachments
-    if (sum_all_stages[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] > dev_data->phys_dev_props.limits.maxDescriptorSetInputAttachments) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (sum_all_stages[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] > device_data->phys_dev_props.limits.maxDescriptorSetInputAttachments) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01684",
                         "vkCreatePipelineLayout(): sum of input attachment bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetInputAttachments limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT],
-                        dev_data->phys_dev_props.limits.maxDescriptorSetInputAttachments);
+                        device_data->phys_dev_props.limits.maxDescriptorSetInputAttachments);
     }
 
     // Inline uniform blocks
     if (sum_all_stages[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT] >
-        dev_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        device_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkPipelineLayoutCreateInfo-descriptorType-02216",
                         "vkCreatePipelineLayout(): sum of inline uniform block bindings among all stages (%d) exceeds device "
                         "maxDescriptorSetInlineUniformBlocks limit (%d).",
                         sum_all_stages[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
-                        dev_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks);
+                        device_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks);
     }
 
-    if (dev_data->extensions.vk_ext_descriptor_indexing) {
+    if (device_data->device_extensions.vk_ext_descriptor_indexing) {
         // XXX TODO: replace with correct VU messages
 
         // Max descriptors by type, within a single pipeline stage
         std::valarray<uint32_t> max_descriptors_per_stage_update_after_bind =
-            GetDescriptorCountMaxPerStage(dev_data, set_layouts, false);
+            GetDescriptorCountMaxPerStage(device_data, set_layouts, false);
         // Samplers
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLERS] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSamplers) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSamplers) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-VkPipelineLayoutCreateInfo-descriptorType-03022",
                             "vkCreatePipelineLayout(): max per-stage sampler bindings count (%d) exceeds device "
                             "maxPerStageDescriptorUpdateAfterBindSamplers limit (%d).",
                             max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLERS],
-                            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSamplers);
+                            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSamplers);
         }
 
         // Uniform buffers
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_UNIFORM_BUFFERS] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindUniformBuffers) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-descriptorType-03023",
-                        "vkCreatePipelineLayout(): max per-stage uniform buffer bindings count (%d) exceeds device "
-                        "maxPerStageDescriptorUpdateAfterBindUniformBuffers limit (%d).",
-                        max_descriptors_per_stage_update_after_bind[DSL_TYPE_UNIFORM_BUFFERS],
-                        dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindUniformBuffers);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindUniformBuffers) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkPipelineLayoutCreateInfo-descriptorType-03023",
+                "vkCreatePipelineLayout(): max per-stage uniform buffer bindings count (%d) exceeds device "
+                "maxPerStageDescriptorUpdateAfterBindUniformBuffers limit (%d).",
+                max_descriptors_per_stage_update_after_bind[DSL_TYPE_UNIFORM_BUFFERS],
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindUniformBuffers);
         }
 
         // Storage buffers
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_BUFFERS] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageBuffers) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-descriptorType-03024",
-                        "vkCreatePipelineLayout(): max per-stage storage buffer bindings count (%d) exceeds device "
-                        "maxPerStageDescriptorUpdateAfterBindStorageBuffers limit (%d).",
-                        max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_BUFFERS],
-                        dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageBuffers);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageBuffers) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkPipelineLayoutCreateInfo-descriptorType-03024",
+                "vkCreatePipelineLayout(): max per-stage storage buffer bindings count (%d) exceeds device "
+                "maxPerStageDescriptorUpdateAfterBindStorageBuffers limit (%d).",
+                max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_BUFFERS],
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageBuffers);
         }
 
         // Sampled images
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLED_IMAGES] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSampledImages) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-descriptorType-03025",
-                        "vkCreatePipelineLayout(): max per-stage sampled image bindings count (%d) exceeds device "
-                        "maxPerStageDescriptorUpdateAfterBindSampledImages limit (%d).",
-                        max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLED_IMAGES],
-                        dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSampledImages);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSampledImages) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkPipelineLayoutCreateInfo-descriptorType-03025",
+                "vkCreatePipelineLayout(): max per-stage sampled image bindings count (%d) exceeds device "
+                "maxPerStageDescriptorUpdateAfterBindSampledImages limit (%d).",
+                max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLED_IMAGES],
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindSampledImages);
         }
 
         // Storage images
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_IMAGES] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageImages) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-descriptorType-03026",
-                        "vkCreatePipelineLayout(): max per-stage storage image bindings count (%d) exceeds device "
-                        "maxPerStageDescriptorUpdateAfterBindStorageImages limit (%d).",
-                        max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_IMAGES],
-                        dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageImages);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageImages) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkPipelineLayoutCreateInfo-descriptorType-03026",
+                "vkCreatePipelineLayout(): max per-stage storage image bindings count (%d) exceeds device "
+                "maxPerStageDescriptorUpdateAfterBindStorageImages limit (%d).",
+                max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_IMAGES],
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindStorageImages);
         }
 
         // Input attachments
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_INPUT_ATTACHMENTS] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindInputAttachments) {
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindInputAttachments) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkPipelineLayoutCreateInfo-descriptorType-03027",
                 "vkCreatePipelineLayout(): max per-stage input attachment bindings count (%d) exceeds device "
                 "maxPerStageDescriptorUpdateAfterBindInputAttachments limit (%d).",
                 max_descriptors_per_stage_update_after_bind[DSL_TYPE_INPUT_ATTACHMENTS],
-                dev_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindInputAttachments);
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxPerStageDescriptorUpdateAfterBindInputAttachments);
         }
 
         // Inline uniform blocks
         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_INLINE_UNIFORM_BLOCK] >
-            dev_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks) {
+            device_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkPipelineLayoutCreateInfo-descriptorType-02215",
                 "vkCreatePipelineLayout(): max per-stage inline uniform block bindings count (%d) exceeds device "
                 "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks limit (%d).",
                 max_descriptors_per_stage_update_after_bind[DSL_TYPE_INLINE_UNIFORM_BLOCK],
-                dev_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks);
+                device_data->phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks);
         }
 
         // Total descriptors by type, summed across all pipeline stages
         //
-        std::map<uint32_t, uint32_t> sum_all_stages_update_after_bind = GetDescriptorSum(dev_data, set_layouts, false);
+        std::map<uint32_t, uint32_t> sum_all_stages_update_after_bind = GetDescriptorSum(device_data, set_layouts, false);
         // Samplers
         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_SAMPLER] +
               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER];
-        if (sum > dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSamplers) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        if (sum > device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSamplers) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03036",
                             "vkCreatePipelineLayout(): sum of sampler bindings among all stages (%d) exceeds device "
                             "maxDescriptorSetUpdateAfterBindSamplers limit (%d).",
-                            sum, dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSamplers);
+                            sum, device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSamplers);
         }
 
         // Uniform buffers
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffers) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03037",
-                            "vkCreatePipelineLayout(): sum of uniform buffer bindings among all stages (%d) exceeds device "
-                            "maxDescriptorSetUpdateAfterBindUniformBuffers limit (%d).",
-                            sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER],
-                            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffers);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffers) {
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03037",
+                        "vkCreatePipelineLayout(): sum of uniform buffer bindings among all stages (%d) exceeds device "
+                        "maxDescriptorSetUpdateAfterBindUniformBuffers limit (%d).",
+                        sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER],
+                        device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffers);
         }
 
         // Dynamic uniform buffers
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic) {
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03038",
                 "vkCreatePipelineLayout(): sum of dynamic uniform buffer bindings among all stages (%d) exceeds device "
                 "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic limit (%d).",
                 sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC],
-                dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
         }
 
         // Storage buffers
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffers) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03039",
-                            "vkCreatePipelineLayout(): sum of storage buffer bindings among all stages (%d) exceeds device "
-                            "maxDescriptorSetUpdateAfterBindStorageBuffers limit (%d).",
-                            sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER],
-                            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffers);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffers) {
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03039",
+                        "vkCreatePipelineLayout(): sum of storage buffer bindings among all stages (%d) exceeds device "
+                        "maxDescriptorSetUpdateAfterBindStorageBuffers limit (%d).",
+                        sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER],
+                        device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffers);
         }
 
         // Dynamic storage buffers
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic) {
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03040",
                 "vkCreatePipelineLayout(): sum of dynamic storage buffer bindings among all stages (%d) exceeds device "
                 "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic limit (%d).",
                 sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC],
-                dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic);
+                device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic);
         }
 
         //  Sampled images
         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] +
               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] +
               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER];
-        if (sum > dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSampledImages) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03041",
-                        "vkCreatePipelineLayout(): sum of sampled image bindings among all stages (%d) exceeds device "
-                        "maxDescriptorSetUpdateAfterBindSampledImages limit (%d).",
-                        sum, dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSampledImages);
+        if (sum > device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSampledImages) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03041",
+                            "vkCreatePipelineLayout(): sum of sampled image bindings among all stages (%d) exceeds device "
+                            "maxDescriptorSetUpdateAfterBindSampledImages limit (%d).",
+                            sum,
+                            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindSampledImages);
         }
 
         //  Storage images
         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] +
               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER];
-        if (sum > dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageImages) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03042",
-                        "vkCreatePipelineLayout(): sum of storage image bindings among all stages (%d) exceeds device "
-                        "maxDescriptorSetUpdateAfterBindStorageImages limit (%d).",
-                        sum, dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageImages);
+        if (sum > device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageImages) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03042",
+                            "vkCreatePipelineLayout(): sum of storage image bindings among all stages (%d) exceeds device "
+                            "maxDescriptorSetUpdateAfterBindStorageImages limit (%d).",
+                            sum,
+                            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindStorageImages);
         }
 
         // Input attachments
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] >
-            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindInputAttachments) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03043",
-                            "vkCreatePipelineLayout(): sum of input attachment bindings among all stages (%d) exceeds device "
-                            "maxDescriptorSetUpdateAfterBindInputAttachments limit (%d).",
-                            sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT],
-                            dev_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindInputAttachments);
+            device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindInputAttachments) {
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03043",
+                        "vkCreatePipelineLayout(): sum of input attachment bindings among all stages (%d) exceeds device "
+                        "maxDescriptorSetUpdateAfterBindInputAttachments limit (%d).",
+                        sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT],
+                        device_data->phys_dev_ext_props.descriptor_indexing_props.maxDescriptorSetUpdateAfterBindInputAttachments);
         }
 
         // Inline uniform blocks
         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT] >
-            dev_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks) {
-            skip |=
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                        "VUID-VkPipelineLayoutCreateInfo-descriptorType-02217",
-                        "vkCreatePipelineLayout(): sum of inline uniform block bindings among all stages (%d) exceeds device "
-                        "maxDescriptorSetUpdateAfterBindInlineUniformBlocks limit (%d).",
-                        sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
-                        dev_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks);
+            device_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkPipelineLayoutCreateInfo-descriptorType-02217",
+                "vkCreatePipelineLayout(): sum of inline uniform block bindings among all stages (%d) exceeds device "
+                "maxDescriptorSetUpdateAfterBindInlineUniformBlocks limit (%d).",
+                sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
+                device_data->phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks);
         }
     }
     return skip;
@@ -5950,16 +6020,34 @@
     return pipeline_layout_compat_dict.look_up(PipelineLayoutCompatDef(set_index, pcr_id, set_layouts_id));
 }
 
-static void PostCallRecordCreatePipelineLayout(layer_data *dev_data, const VkPipelineLayoutCreateInfo *pCreateInfo,
-                                               const VkPipelineLayout *pPipelineLayout) {
-    unique_lock_t lock(global_lock);  // Lock while accessing state
+void CoreChecks::PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
+                                                   void *cpl_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    create_pipeline_layout_api_state *cpl_state = reinterpret_cast<create_pipeline_layout_api_state *>(cpl_state_data);
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallCreatePipelineLayout(device_data, pCreateInfo, pAllocator, pPipelineLayout, &cpl_state->new_layouts,
+                                       &cpl_state->modified_create_info);
+    }
+}
 
-    PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
+void CoreChecks::PostCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
+                                                    VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    // Clean up GPU validation
+    if (GetEnables()->gpu_validation) {
+        GpuPostCallCreatePipelineLayout(device_data, result);
+    }
+    if (VK_SUCCESS != result) return;
+
+    PIPELINE_LAYOUT_NODE &plNode = device_data->pipelineLayoutMap[*pPipelineLayout];
     plNode.layout = *pPipelineLayout;
     plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
     PipelineLayoutSetLayoutsDef set_layouts(pCreateInfo->setLayoutCount);
     for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
-        plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
+        plNode.set_layouts[i] = GetDescriptorSetLayout(device_data, pCreateInfo->pSetLayouts[i]);
         set_layouts[i] = plNode.set_layouts[i]->GetLayoutId();
     }
 
@@ -5972,70 +6060,32 @@
     for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
         plNode.compat_for_set.emplace_back(GetCanonicalId(i, plNode.push_constant_ranges, set_layouts_id));
     }
+}
 
-    // Implicit unlock
-};
-
-VKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
+void CoreChecks::PostCallRecordCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool,
+                                                    VkResult result) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    bool skip = PreCallValiateCreatePipelineLayout(dev_data, pCreateInfo);
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
-
-    if (VK_SUCCESS == result) {
-        PostCallRecordCreatePipelineLayout(dev_data, pCreateInfo, pPipelineLayout);
-    }
-    return result;
-}
-
-static bool PostCallValidateCreateDescriptorPool(layer_data *dev_data, VkDescriptorPool *pDescriptorPool) {
-    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                   HandleToUint64(*pDescriptorPool), kVUID_Core_DrawState_OutOfMemory,
-                   "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()");
-}
-
-static void PostCallRecordCreateDescriptorPool(layer_data *dev_data, DESCRIPTOR_POOL_STATE *pNewNode,
-                                               VkDescriptorPool *pDescriptorPool) {
+    if (VK_SUCCESS != result) return;
+    DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
+    assert(pNewNode);
     dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
-    if (VK_SUCCESS == result) {
-        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
-        lock_guard_t lock(global_lock);
-        if (NULL == pNewNode) {
-            bool skip = PostCallValidateCreateDescriptorPool(dev_data, pDescriptorPool);
-            if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-        } else {
-            PostCallRecordCreateDescriptorPool(dev_data, pNewNode, pDescriptorPool);
-        }
-    } else {
-        // Need to do anything if pool create fails?
-    }
-    return result;
-}
-
-// Validate that given pool does not store any descriptor sets used by an in-flight CmdBuffer
-// pool stores the descriptor sets to be validated
-// Return false if no errors occur
-// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
-static bool PreCallValidateResetDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool) {
-    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
+bool CoreChecks::PreCallValidateResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                    VkDescriptorPoolResetFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    // Make sure sets being destroyed are not currently in-use
+    if (device_data->instance_data->disabled.idle_descriptor_set) return false;
     bool skip = false;
-    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, descriptorPool);
+    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(descriptorPool);
     if (pPool != nullptr) {
         for (auto ds : pPool->sets) {
             if (ds && ds->in_use.load()) {
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                            HandleToUint64(descriptorPool), "VUID-vkResetDescriptorPool-descriptorPool-00313",
-                            "It is invalid to call vkResetDescriptorPool() with descriptor sets in use by a command buffer.");
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, HandleToUint64(descriptorPool),
+                                "VUID-vkResetDescriptorPool-descriptorPool-00313",
+                                "It is invalid to call vkResetDescriptorPool() with descriptor sets in use by a command buffer.");
                 if (skip) break;
             }
         }
@@ -6043,13 +6093,15 @@
     return skip;
 }
 
-static void PostCallRecordResetDescriptorPool(layer_data *dev_data, VkDevice device, VkDescriptorPool descriptorPool,
-                                              VkDescriptorPoolResetFlags flags) {
-    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, descriptorPool);
+void CoreChecks::PostCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                   VkDescriptorPoolResetFlags flags, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(descriptorPool);
     // TODO: validate flags
     // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
     for (auto ds : pPool->sets) {
-        FreeDescriptorSet(dev_data, ds);
+        FreeDescriptorSet(device_data, ds);
     }
     pPool->sets.clear();
     // Reset available count for each type and available sets for this pool
@@ -6059,137 +6111,84 @@
     pPool->availableSets = pPool->maxSets;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
-                                                   VkDescriptorPoolResetFlags flags) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    // Make sure sets being destroyed are not currently in-use
-    bool skip = PreCallValidateResetDescriptorPool(dev_data, descriptorPool);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordResetDescriptorPool(dev_data, device, descriptorPool, flags);
-        lock.unlock();
-    }
-    return result;
-}
-
 // Ensure the pool contains enough descriptors and descriptor sets to satisfy
 // an allocation request. Fills common_data with the total number of descriptors of each type required,
 // as well as DescriptorSetLayout ptrs used for later update.
-static bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
-                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
+bool CoreChecks::PreCallValidateAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                       VkDescriptorSet *pDescriptorSets, void *ads_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     // Always update common data
-    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
-    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
+    cvdescriptorset::AllocateDescriptorSetsData *ads_state =
+        reinterpret_cast<cvdescriptorset::AllocateDescriptorSetsData *>(ads_state_data);
+    UpdateAllocateDescriptorSetsData(device_data, pAllocateInfo, ads_state);
+    if (device_data->instance_data->disabled.allocate_descriptor_sets) return false;
     // All state checks for AllocateDescriptorSets is done in single function
-    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
+    return ValidateAllocateDescriptorSets(device_data, pAllocateInfo, ads_state);
 }
+
 // Allocation state was good and call down chain was made so update state based on allocating descriptor sets
-static void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
-                                                 VkDescriptorSet *pDescriptorSets,
-                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
+void CoreChecks::PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                      VkDescriptorSet *pDescriptorSets, VkResult result, void *ads_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
     // All the updates are contained in a single cvdescriptorset function
-    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
-                                                   &dev_data->setMap, dev_data);
+    cvdescriptorset::AllocateDescriptorSetsData *ads_state =
+        reinterpret_cast<cvdescriptorset::AllocateDescriptorSetsData *>(ads_state_data);
+    PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, ads_state, &device_data->descriptorPoolMap, &device_data->setMap,
+                                  device_data);
 }
 
-// TODO: PostCallRecord routine is dependent on data generated in PreCallValidate -- needs to be moved out
-VKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
-                                                      VkDescriptorSet *pDescriptorSets) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
-    bool skip = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
-        lock.unlock();
-    }
-    return result;
-}
-// Verify state before freeing DescriptorSets
-static bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
-                                              const VkDescriptorSet *descriptor_sets) {
-    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
+bool CoreChecks::PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
+                                                   const VkDescriptorSet *pDescriptorSets) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    // Make sure that no sets being destroyed are in-flight
     bool skip = false;
     // First make sure sets being destroyed are not currently in-use
     for (uint32_t i = 0; i < count; ++i) {
-        if (descriptor_sets[i] != VK_NULL_HANDLE) {
-            skip |= ValidateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
+        if (pDescriptorSets[i] != VK_NULL_HANDLE) {
+            skip |= ValidateIdleDescriptorSet(device_data, pDescriptorSets[i], "vkFreeDescriptorSets");
         }
     }
-
-    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
+    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(descriptorPool);
     if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
         // Can't Free from a NON_FREE pool
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                        HandleToUint64(pool), "VUID-vkFreeDescriptorSets-descriptorPool-00312",
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
+                        HandleToUint64(descriptorPool), "VUID-vkFreeDescriptorSets-descriptorPool-00312",
                         "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
                         "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT.");
     }
     return skip;
 }
-// Sets are being returned to the pool so update the pool state
-static void PreCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
-                                            const VkDescriptorSet *descriptor_sets) {
-    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
+
+void CoreChecks::PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
+                                                 const VkDescriptorSet *pDescriptorSets) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(descriptorPool);
     // Update available descriptor sets in pool
     pool_state->availableSets += count;
 
     // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
     for (uint32_t i = 0; i < count; ++i) {
-        if (descriptor_sets[i] != VK_NULL_HANDLE) {
-            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
+        if (pDescriptorSets[i] != VK_NULL_HANDLE) {
+            auto descriptor_set = device_data->setMap[pDescriptorSets[i]];
             uint32_t type_index = 0, descriptor_count = 0;
             for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
                 type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
                 descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
                 pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
             }
-            FreeDescriptorSet(dev_data, descriptor_set);
+            FreeDescriptorSet(device_data, descriptor_set);
             pool_state->sets.erase(descriptor_set);
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
-                                                  const VkDescriptorSet *pDescriptorSets) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // Make sure that no sets being destroyed are in-flight
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
-
-    VkResult result;
-    if (skip) {
-        result = VK_ERROR_VALIDATION_FAILED_EXT;
-    } else {
-        // A race here is invalid (descriptorPool should be externally sync'd), but code defensively against an invalid race
-        PreCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
-        lock.unlock();
-        result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
-    }
-    return result;
-}
-// TODO : This is a Proof-of-concept for core validation architecture
-//  Really we'll want to break out these functions to separate files but
-//  keeping it all together here to prove out design
-// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
-static bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
-                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
-                                                const VkCopyDescriptorSet *pDescriptorCopies) {
-    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
+bool CoreChecks::PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                                     const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
+                                                     const VkCopyDescriptorSet *pDescriptorCopies) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (device_data->disabled.update_descriptor_sets) return false;
     // First thing to do is perform map look-ups.
     // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
     //  so we can't just do a single map look-up up-front, but do them individually in functions below
@@ -6197,179 +6196,154 @@
     // Now make call(s) that validate state, but don't perform state updates in this function
     // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
     //  namespace which will parse params and make calls into specific class instances
-    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
-                                                         descriptorCopyCount, pDescriptorCopies);
+    return ValidateUpdateDescriptorSets(device_data->report_data, device_data, descriptorWriteCount, pDescriptorWrites,
+                                        descriptorCopyCount, pDescriptorCopies, "vkUpdateDescriptorSets()");
 }
-// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
-static void PreCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
-                                              const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
-                                              const VkCopyDescriptorSet *pDescriptorCopies) {
-    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
+
+void CoreChecks::PreCallRecordUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                                   const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
+                                                   const VkCopyDescriptorSet *pDescriptorCopies) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    cvdescriptorset::PerformUpdateDescriptorSets(device_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
                                                  pDescriptorCopies);
 }
 
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
-                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
-                                                const VkCopyDescriptorSet *pDescriptorCopies) {
-    // Only map look-up at top level is for device-level layer_data
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
-                                                    pDescriptorCopies);
-    if (!skip) {
-        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state & we can update before call down chain
-        PreCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
-                                          pDescriptorCopies);
-        lock.unlock();
-        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
-                                                      pDescriptorCopies);
-    }
-}
-
-static void PostCallRecordAllocateCommandBuffers(layer_data *dev_data, VkDevice device,
-                                                 const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) {
-    auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
+void CoreChecks::PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
+                                                      VkCommandBuffer *pCommandBuffer, VkResult result) {
+    if (VK_SUCCESS != result) return;
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto pPool = GetCommandPoolNode(pCreateInfo->commandPool);
     if (pPool) {
         for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
             // Add command buffer to its commandPool map
             pPool->commandBuffers.insert(pCommandBuffer[i]);
             GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
             // Add command buffer to map
-            dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
-            ResetCommandBufferState(dev_data, pCommandBuffer[i]);
+            device_data->commandBufferMap[pCommandBuffer[i]] = pCB;
+            ResetCommandBufferState(device_data, pCommandBuffer[i]);
             pCB->createInfo = *pCreateInfo;
             pCB->device = device;
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
-                                                      VkCommandBuffer *pCommandBuffer) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
-    if (VK_SUCCESS == result) {
-        unique_lock_t lock(global_lock);
-        PostCallRecordAllocateCommandBuffers(dev_data, device, pCreateInfo, pCommandBuffer);
-        lock.unlock();
-    }
-    return result;
-}
-
 // Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
-static void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
+void CoreChecks::AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
     AddCommandBufferBinding(&fb_state->cb_bindings, {HandleToUint64(fb_state->framebuffer), kVulkanObjectTypeFramebuffer},
                             cb_state);
 
     const uint32_t attachmentCount = fb_state->createInfo.attachmentCount;
     for (uint32_t attachment = 0; attachment < attachmentCount; ++attachment) {
-        auto view_state = GetAttachmentImageViewState(dev_data, fb_state, attachment);
+        auto view_state = GetAttachmentImageViewState(fb_state, attachment);
         if (view_state) {
             AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
         }
     }
 }
 
-static bool PreCallValidateBeginCommandBuffer(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state,
-                                              const VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
-    assert(cb_state);
+bool CoreChecks::PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    if (!cb_state) return false;
     bool skip = false;
     if (cb_state->in_use.load()) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00049",
-                        "Calling vkBeginCommandBuffer() on active command buffer %" PRIx64
-                        " before it has completed. You must check command buffer fence before this call.",
-                        HandleToUint64(commandBuffer));
+                        "Calling vkBeginCommandBuffer() on active command buffer %s before it has completed. You must check "
+                        "command buffer fence before this call.",
+                        device_data->report_data->FormatHandle(commandBuffer).c_str());
     }
     if (cb_state->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
         // Secondary Command Buffer
         const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
         if (!pInfo) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00051",
-                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%" PRIx64 ") must have inheritance info.",
-                            HandleToUint64(commandBuffer));
+                            "vkBeginCommandBuffer(): Secondary Command Buffer (%s) must have inheritance info.",
+                            device_data->report_data->FormatHandle(commandBuffer).c_str());
         } else {
             if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
                 assert(pInfo->renderPass);
-                string errorString = "";
-                auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
+                auto framebuffer = GetFramebufferState(pInfo->framebuffer);
                 if (framebuffer) {
                     if (framebuffer->createInfo.renderPass != pInfo->renderPass) {
                         // renderPass that framebuffer was created with must be compatible with local renderPass
                         skip |=
-                            ValidateRenderPassCompatibility(dev_data, "framebuffer", framebuffer->rp_state.get(), "command buffer",
-                                                            GetRenderPassState(dev_data, pInfo->renderPass),
+                            ValidateRenderPassCompatibility(device_data, "framebuffer", framebuffer->rp_state.get(),
+                                                            "command buffer", GetRenderPassState(pInfo->renderPass),
                                                             "vkBeginCommandBuffer()", "VUID-VkCommandBufferBeginInfo-flags-00055");
                     }
                 }
             }
-            if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.core.occlusionQueryPrecise == VK_FALSE) &&
+            if ((pInfo->occlusionQueryEnable == VK_FALSE || device_data->enabled_features.core.occlusionQueryPrecise == VK_FALSE) &&
                 (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
                 skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00052",
-                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%" PRIx64
-                            ") must not have VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device "
-                            "does not support precise occlusion queries.",
-                            HandleToUint64(commandBuffer));
+                            "vkBeginCommandBuffer(): Secondary Command Buffer (%s) must not have VK_QUERY_CONTROL_PRECISE_BIT if "
+                            "occulusionQuery is disabled or the device does not support precise occlusion queries.",
+                            device_data->report_data->FormatHandle(commandBuffer).c_str());
             }
         }
         if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
-            auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
+            auto renderPass = GetRenderPassState(pInfo->renderPass);
             if (renderPass) {
                 if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer),
                                     "VUID-VkCommandBufferBeginInfo-flags-00054",
-                                    "vkBeginCommandBuffer(): Secondary Command Buffers (0x%" PRIx64
-                                    ") must have a subpass index (%d) that is less than the number of subpasses (%d).",
-                                    HandleToUint64(commandBuffer), pInfo->subpass, renderPass->createInfo.subpassCount);
+                                    "vkBeginCommandBuffer(): Secondary Command Buffers (%s) must have a subpass index (%d) that is "
+                                    "less than the number of subpasses (%d).",
+                                    device_data->report_data->FormatHandle(commandBuffer).c_str(), pInfo->subpass,
+                                    renderPass->createInfo.subpassCount);
                 }
             }
         }
     }
     if (CB_RECORDING == cb_state->state) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00049",
-                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%" PRIx64
-                        ") in the RECORDING state. Must first call vkEndCommandBuffer().",
-                        HandleToUint64(commandBuffer));
+                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (%s) in the RECORDING state. Must first call "
+                        "vkEndCommandBuffer().",
+                        device_data->report_data->FormatHandle(commandBuffer).c_str());
     } else if (CB_RECORDED == cb_state->state || CB_INVALID_COMPLETE == cb_state->state) {
         VkCommandPool cmdPool = cb_state->createInfo.commandPool;
-        auto pPool = GetCommandPoolNode(dev_data, cmdPool);
+        auto pPool = GetCommandPoolNode(cmdPool);
         if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00050",
-                            "Call to vkBeginCommandBuffer() on command buffer (0x%" PRIx64
-                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIx64
-                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
-                            HandleToUint64(commandBuffer), HandleToUint64(cmdPool));
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkBeginCommandBuffer-commandBuffer-00050",
+                        "Call to vkBeginCommandBuffer() on command buffer (%s) attempts to implicitly reset cmdBuffer created from "
+                        "command pool (%s) that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
+                        device_data->report_data->FormatHandle(commandBuffer).c_str(),
+                        device_data->report_data->FormatHandle(cmdPool).c_str());
         }
     }
     return skip;
 }
 
-static void PreCallRecordBeginCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkCommandBuffer commandBuffer,
-                                            const VkCommandBufferBeginInfo *pBeginInfo) {
-    assert(cb_state);
+void CoreChecks::PreCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    if (!cb_state) return;
     // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
-    ClearCmdBufAndMemReferences(dev_data, cb_state);
+    ClearCmdBufAndMemReferences(device_data, cb_state);
     if (cb_state->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
         // Secondary Command Buffer
         const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
         if (pInfo) {
             if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
                 assert(pInfo->renderPass);
-                auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
+                auto framebuffer = GetFramebufferState(pInfo->framebuffer);
                 if (framebuffer) {
                     // Connect this framebuffer and its children to this cmdBuffer
-                    AddFramebufferBinding(dev_data, cb_state, framebuffer);
+                    AddFramebufferBinding(device_data, cb_state, framebuffer);
                 }
             }
         }
     }
     if (CB_RECORDED == cb_state->state || CB_INVALID_COMPLETE == cb_state->state) {
-        ResetCommandBufferState(dev_data, commandBuffer);
+        ResetCommandBufferState(device_data, commandBuffer);
     }
     // Set updated state here in case implicit reset occurs above
     cb_state->state = CB_RECORDING;
@@ -6380,7 +6354,7 @@
         // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
         if ((cb_state->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
             (cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
-            cb_state->activeRenderPass = GetRenderPassState(dev_data, cb_state->beginInfo.pInheritanceInfo->renderPass);
+            cb_state->activeRenderPass = GetRenderPassState(cb_state->beginInfo.pInheritanceInfo->renderPass);
             cb_state->activeSubpass = cb_state->beginInfo.pInheritanceInfo->subpass;
             cb_state->activeFramebuffer = cb_state->beginInfo.pInheritanceInfo->framebuffer;
             cb_state->framebuffers.insert(cb_state->beginInfo.pInheritanceInfo->framebuffer);
@@ -6388,44 +6362,30 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    // Validate command buffer level
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateBeginCommandBuffer(dev_data, cb_state, commandBuffer, pBeginInfo);
-        PreCallRecordBeginCommandBuffer(dev_data, cb_state, commandBuffer, pBeginInfo);
-    }
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
-
-    return result;
-}
-
-static bool PreCallValidateEndCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
+bool CoreChecks::PreCallValidateEndCommandBuffer(VkCommandBuffer commandBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    if (!cb_state) return false;
     bool skip = false;
     if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == cb_state->createInfo.level) ||
         !(cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
         // This needs spec clarification to update valid usage, see comments in PR:
         // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/165
-        skip |= InsideRenderPass(dev_data, cb_state, "vkEndCommandBuffer()", "VUID-vkEndCommandBuffer-commandBuffer-00060");
+        skip |= InsideRenderPass(device_data, cb_state, "vkEndCommandBuffer()", "VUID-vkEndCommandBuffer-commandBuffer-00060");
     }
-    skip |= ValidateCmd(dev_data, cb_state, CMD_ENDCOMMANDBUFFER, "vkEndCommandBuffer()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_ENDCOMMANDBUFFER, "vkEndCommandBuffer()");
     for (auto query : cb_state->activeQueries) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkEndCommandBuffer-commandBuffer-00061",
-                        "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d.",
-                        HandleToUint64(query.pool), query.index);
+                        "Ending command buffer with in progress query: queryPool %s, index %d.",
+                        device_data->report_data->FormatHandle(query.pool).c_str(), query.index);
     }
     return skip;
 }
 
-static void PostCallRecordEndCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkResult &result) {
+void CoreChecks::PostCallRecordEndCommandBuffer(VkCommandBuffer commandBuffer, VkResult result) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    if (!cb_state) return;
     // Cached validation is specific to a specific recording of a specific command buffer.
     for (auto descriptor_set : cb_state->validated_descriptor_sets) {
         descriptor_set->ClearCachedValidation(cb_state);
@@ -6436,80 +6396,54 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
+bool CoreChecks::PreCallValidateResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateEndCommandBuffer(dev_data, cb_state, commandBuffer);
-    }
-    if (!skip) {
-        lock.unlock();
-        auto result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
-        lock.lock();
-        if (cb_state) {
-            PostCallRecordEndCommandBuffer(dev_data, cb_state, result);
-        }
-        return result;
-    } else {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-}
-
-static bool PreCallValidateResetCommandBuffer(layer_data *dev_data, VkCommandBuffer commandBuffer) {
-    bool skip = false;
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
+    GLOBAL_CB_NODE *pCB = GetCBNode(commandBuffer);
+    if (!pCB) return false;
     VkCommandPool cmdPool = pCB->createInfo.commandPool;
-    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
+    auto pPool = GetCommandPoolNode(cmdPool);
 
     if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkResetCommandBuffer-commandBuffer-00046",
-                        "Attempt to reset command buffer (0x%" PRIx64 ") created from command pool (0x%" PRIx64
-                        ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
-                        HandleToUint64(commandBuffer), HandleToUint64(cmdPool));
+                        "Attempt to reset command buffer (%s) created from command pool (%s) that does NOT have the "
+                        "VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
+                        device_data->report_data->FormatHandle(commandBuffer).c_str(),
+                        device_data->report_data->FormatHandle(cmdPool).c_str());
     }
-    skip |= CheckCommandBufferInFlight(dev_data, pCB, "reset", "VUID-vkResetCommandBuffer-commandBuffer-00045");
+    skip |= CheckCommandBufferInFlight(device_data, pCB, "reset", "VUID-vkResetCommandBuffer-commandBuffer-00045");
 
     return skip;
 }
 
-static void PostCallRecordResetCommandBuffer(layer_data *dev_data, VkCommandBuffer commandBuffer) {
-    ResetCommandBufferState(dev_data, commandBuffer);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateResetCommandBuffer(dev_data, commandBuffer);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
-
+void CoreChecks::PostCallRecordResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags, VkResult result) {
     if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordResetCommandBuffer(dev_data, commandBuffer);
-        lock.unlock();
+        layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+        ResetCommandBufferState(device_data, commandBuffer);
     }
-
-    return result;
 }
 
-static bool PreCallValidateCmdBindPipeline(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+bool CoreChecks::PreCallValidateCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                VkPipeline pipeline) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                       "VUID-vkCmdBindPipeline-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
     // TODO: "VUID-vkCmdBindPipeline-pipelineBindPoint-00777" "VUID-vkCmdBindPipeline-pipelineBindPoint-00779"  -- using
     // ValidatePipelineBindPoint
     return skip;
 }
 
-static void PreCallRecordCmdBindPipeline(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint pipelineBindPoint,
-                                         VkPipeline pipeline) {
-    auto pipe_state = GetPipelineState(dev_data, pipeline);
+void CoreChecks::PreCallRecordCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                              VkPipeline pipeline) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+
+    auto pipe_state = GetPipelineState(pipeline);
     if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
         cb_state->status &= ~cb_state->static_status;
         cb_state->static_status = MakeStaticStateMask(pipe_state->graphicsPipelineCI.ptr()->pDynamicState);
@@ -6520,98 +6454,68 @@
     AddCommandBufferBinding(&pipe_state->cb_bindings, {HandleToUint64(pipeline), kVulkanObjectTypePipeline}, cb_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
-                                           VkPipeline pipeline) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdBindPipeline(dev_data, cb_state);
-        PreCallRecordCmdBindPipeline(dev_data, cb_state, pipelineBindPoint, pipeline);
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
-}
-
-static bool PreCallValidateCmdSetViewport(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+                                               const VkViewport *pViewports) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetViewport-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETVIEWPORT, "vkCmdSetViewport()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETVIEWPORT, "vkCmdSetViewport()");
     if (cb_state->static_status & CBSTATUS_VIEWPORT_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetViewport-None-01221",
-                        "vkCmdSetViewport(): pipeline was created without VK_DYNAMIC_STATE_VIEWPORT flag..");
+                        "vkCmdSetViewport(): pipeline was created without VK_DYNAMIC_STATE_VIEWPORT flag.");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetViewport(GLOBAL_CB_NODE *cb_state, uint32_t firstViewport, uint32_t viewportCount) {
+void CoreChecks::PreCallRecordCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+                                             const VkViewport *pViewports) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     cb_state->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
     cb_state->status |= CBSTATUS_VIEWPORT_SET;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
-                                          const VkViewport *pViewports) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetViewport(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetViewport(pCB, firstViewport, viewportCount);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
-}
-
-static bool PreCallValidateCmdSetScissor(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
+                                              const VkRect2D *pScissors) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetScissor-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETSCISSOR, "vkCmdSetScissor()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETSCISSOR, "vkCmdSetScissor()");
     if (cb_state->static_status & CBSTATUS_SCISSOR_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetScissor-None-00590",
                         "vkCmdSetScissor(): pipeline was created without VK_DYNAMIC_STATE_SCISSOR flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetScissor(GLOBAL_CB_NODE *cb_state, uint32_t firstScissor, uint32_t scissorCount) {
+void CoreChecks::PreCallRecordCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
+                                            const VkRect2D *pScissors) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     cb_state->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
     cb_state->status |= CBSTATUS_SCISSOR_SET;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
-                                         const VkRect2D *pScissors) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetScissor(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetScissor(pCB, firstScissor, scissorCount);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
-}
-
-static bool PreCallValidateCmdSetExclusiveScissorNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetExclusiveScissorNV()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
+                                                         uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetExclusiveScissorNV()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetExclusiveScissorNV-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETEXCLUSIVESCISSOR, "vkCmdSetExclusiveScissorNV()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETEXCLUSIVESCISSOR, "vkCmdSetExclusiveScissorNV()");
     if (cb_state->static_status & CBSTATUS_EXCLUSIVE_SCISSOR_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-None-02032",
                         "vkCmdSetExclusiveScissorNV(): pipeline was created without VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV flag.");
     }
 
-    if (!GetEnabledFeatures(dev_data)->exclusive_scissor.exclusiveScissor) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+    if (!GetEnabledFeatures()->exclusive_scissor.exclusiveScissor) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-None-02031",
                         "vkCmdSetExclusiveScissorNV: The exclusiveScissor feature is disabled.");
     }
@@ -6619,50 +6523,36 @@
     return skip;
 }
 
-static void PreCallRecordCmdSetExclusiveScissorNV(GLOBAL_CB_NODE *cb_state, uint32_t firstExclusiveScissor,
-                                                  uint32_t exclusiveScissorCount) {
-    // XXX TODO: We don't have VUIDs for validating that all exclusive scissors have been set.
+void CoreChecks::PreCallRecordCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
+                                                       uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    // TODO: We don't have VUIDs for validating that all exclusive scissors have been set.
     // cb_state->exclusiveScissorMask |= ((1u << exclusiveScissorCount) - 1u) << firstExclusiveScissor;
     cb_state->status |= CBSTATUS_EXCLUSIVE_SCISSOR_SET;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
-                                                    uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetExclusiveScissorNV(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetExclusiveScissorNV(pCB, firstExclusiveScissor, exclusiveScissorCount);
-        }
-    }
-    lock.unlock();
-    if (!skip)
-        dev_data->dispatch_table.CmdSetExclusiveScissorNV(commandBuffer, firstExclusiveScissor, exclusiveScissorCount,
-                                                          pExclusiveScissors);
-}
-
-static bool PreCallValidateCmdBindShadingRateImageNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                                     VkImageView imageView, VkImageLayout imageLayout) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindShadingRateImageNV()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView,
+                                                          VkImageLayout imageLayout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdBindShadingRateImageNV()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdBindShadingRateImageNV-commandBuffer-cmdpool");
 
-    skip |= ValidateCmd(dev_data, cb_state, CMD_BINDSHADINGRATEIMAGE, "vkCmdBindShadingRateImageNV()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_BINDSHADINGRATEIMAGE, "vkCmdBindShadingRateImageNV()");
 
-    if (!GetEnabledFeatures(dev_data)->shading_rate_image.shadingRateImage) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+    if (!GetEnabledFeatures()->shading_rate_image.shadingRateImage) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdBindShadingRateImageNV-None-02058",
                         "vkCmdBindShadingRateImageNV: The shadingRateImage feature is disabled.");
     }
 
     if (imageView != VK_NULL_HANDLE) {
-        auto view_state = GetImageViewState(dev_data, imageView);
+        auto view_state = GetImageViewState(imageView);
         auto &ivci = view_state->create_info;
 
         if (!view_state || (ivci.viewType != VK_IMAGE_VIEW_TYPE_2D && ivci.viewType != VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
                             HandleToUint64(imageView), "VUID-vkCmdBindShadingRateImageNV-imageView-02059",
                             "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, it must be a valid "
                             "VkImageView handle of type VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
@@ -6670,21 +6560,21 @@
 
         if (view_state && ivci.format != VK_FORMAT_R8_UINT) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
                 HandleToUint64(imageView), "VUID-vkCmdBindShadingRateImageNV-imageView-02060",
                 "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, it must have a format of VK_FORMAT_R8_UINT.");
         }
 
-        const VkImageCreateInfo *ici = view_state ? &GetImageState(dev_data, view_state->create_info.image)->createInfo : nullptr;
+        const VkImageCreateInfo *ici = view_state ? &GetImageState(view_state->create_info.image)->createInfo : nullptr;
         if (ici && !(ici->usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV)) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
                             HandleToUint64(imageView), "VUID-vkCmdBindShadingRateImageNV-imageView-02061",
                             "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, the image must have been "
                             "created with VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV set.");
         }
 
         if (view_state) {
-            auto image_state = GetImageState(dev_data, view_state->create_info.image);
+            auto image_state = GetImageState(view_state->create_info.image);
             bool hit_error = false;
 
             // XXX TODO: While the VUID says "each subresource", only the base mip level is
@@ -6694,7 +6584,7 @@
             VkImageSubresourceLayers subresource = {range.aspectMask, range.baseMipLevel, range.baseArrayLayer, range.layerCount};
 
             if (image_state) {
-                skip |= VerifyImageLayout(dev_data, cb_state, image_state, subresource, imageLayout,
+                skip |= VerifyImageLayout(device_data, cb_state, image_state, subresource, imageLayout,
                                           VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV, "vkCmdCopyImage()",
                                           "VUID-vkCmdBindShadingRateImageNV-imageLayout-02063",
                                           "VUID-vkCmdBindShadingRateImageNV-imageView-02062", &hit_error);
@@ -6705,46 +6595,36 @@
     return skip;
 }
 
-static void PreCallRecordCmdBindShadingRateImageNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkImageView imageView) {
+void CoreChecks::PreCallRecordCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView,
+                                                        VkImageLayout imageLayout) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+
     if (imageView != VK_NULL_HANDLE) {
-        auto view_state = GetImageViewState(dev_data, imageView);
-        AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
+        auto view_state = GetImageViewState(imageView);
+        AddCommandBufferBindingImageView(device_data, cb_state, view_state);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView,
-                                                     VkImageLayout imageLayout) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdBindShadingRateImageNV(dev_data, pCB, commandBuffer, imageView, imageLayout);
-        if (!skip) {
-            PreCallRecordCmdBindShadingRateImageNV(dev_data, pCB, imageView);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdBindShadingRateImageNV(commandBuffer, imageView, imageLayout);
-}
-
-static bool PreCallValidateCmdSetViewportShadingRatePaletteNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
-                                                              VkCommandBuffer commandBuffer, uint32_t firstViewport,
-                                                              uint32_t viewportCount,
-                                                              const VkShadingRatePaletteNV *pShadingRatePalettes) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetViewportShadingRatePaletteNV()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                                   uint32_t viewportCount,
+                                                                   const VkShadingRatePaletteNV *pShadingRatePalettes) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetViewportShadingRatePaletteNV()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetViewportShadingRatePaletteNV-commandBuffer-cmdpool");
 
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETVIEWPORTSHADINGRATEPALETTE, "vkCmdSetViewportShadingRatePaletteNV()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETVIEWPORTSHADINGRATEPALETTE, "vkCmdSetViewportShadingRatePaletteNV()");
 
-    if (!GetEnabledFeatures(dev_data)->shading_rate_image.shadingRateImage) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+    if (!GetEnabledFeatures()->shading_rate_image.shadingRateImage) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetViewportShadingRatePaletteNV-None-02064",
                         "vkCmdSetViewportShadingRatePaletteNV: The shadingRateImage feature is disabled.");
     }
 
     if (cb_state->static_status & CBSTATUS_SHADING_RATE_PALETTE_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetViewportShadingRatePaletteNV-None-02065",
                         "vkCmdSetViewportShadingRatePaletteNV(): pipeline was created without "
                         "VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV flag.");
@@ -6753,9 +6633,10 @@
     for (uint32_t i = 0; i < viewportCount; ++i) {
         auto *palette = &pShadingRatePalettes[i];
         if (palette->shadingRatePaletteEntryCount == 0 ||
-            palette->shadingRatePaletteEntryCount > dev_data->phys_dev_ext_props.shading_rate_image_props.shadingRatePaletteSize) {
+            palette->shadingRatePaletteEntryCount >
+                device_data->phys_dev_ext_props.shading_rate_image_props.shadingRatePaletteSize) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                 HandleToUint64(commandBuffer), "VUID-VkShadingRatePaletteNV-shadingRatePaletteEntryCount-02071",
                 "vkCmdSetViewportShadingRatePaletteNV: shadingRatePaletteEntryCount must be between 1 and shadingRatePaletteSize.");
         }
@@ -6764,75 +6645,51 @@
     return skip;
 }
 
-static void PreCallRecordCmdSetViewportShadingRatePaletteNV(GLOBAL_CB_NODE *cb_state, uint32_t firstViewport,
-                                                            uint32_t viewportCount) {
-    // XXX TODO: We don't have VUIDs for validating that all shading rate palettes have been set.
+void CoreChecks::PreCallRecordCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                                 uint32_t viewportCount,
+                                                                 const VkShadingRatePaletteNV *pShadingRatePalettes) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    // TODO: We don't have VUIDs for validating that all shading rate palettes have been set.
     // cb_state->shadingRatePaletteMask |= ((1u << viewportCount) - 1u) << firstViewport;
     cb_state->status |= CBSTATUS_SHADING_RATE_PALETTE_SET;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
-                                                              uint32_t viewportCount,
-                                                              const VkShadingRatePaletteNV *pShadingRatePalettes) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetViewportShadingRatePaletteNV(dev_data, pCB, commandBuffer, firstViewport, viewportCount,
-                                                                  pShadingRatePalettes);
-        if (!skip) {
-            PreCallRecordCmdSetViewportShadingRatePaletteNV(pCB, firstViewport, viewportCount);
-        }
-    }
-    lock.unlock();
-    if (!skip)
-        dev_data->dispatch_table.CmdSetViewportShadingRatePaletteNV(commandBuffer, firstViewport, viewportCount,
-                                                                    pShadingRatePalettes);
-}
-
-static bool PreCallValidateCmdSetLineWidth(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetLineWidth-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETLINEWIDTH, "vkCmdSetLineWidth()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETLINEWIDTH, "vkCmdSetLineWidth()");
 
     if (cb_state->static_status & CBSTATUS_LINE_WIDTH_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetLineWidth-None-00787",
                         "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH flag.");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetLineWidth(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_LINE_WIDTH_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetLineWidth(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetLineWidth(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
+void CoreChecks::PreCallRecordCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_LINE_WIDTH_SET;
 }
 
-static bool PreCallValidateCmdSetDepthBias(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                           float depthBiasClamp) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
+                                                float depthBiasSlopeFactor) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetDepthBias-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETDEPTHBIAS, "vkCmdSetDepthBias()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETDEPTHBIAS, "vkCmdSetDepthBias()");
     if (cb_state->static_status & CBSTATUS_DEPTH_BIAS_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetDepthBias-None-00789",
                         "vkCmdSetDepthBias(): pipeline was created without VK_DYNAMIC_STATE_DEPTH_BIAS flag..");
     }
-    if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.core.depthBiasClamp)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+    if ((depthBiasClamp != 0.0) && (!device_data->enabled_features.core.depthBiasClamp)) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetDepthBias-depthBiasClamp-00790",
                         "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp parameter must "
                         "be set to 0.0.");
@@ -6840,170 +6697,116 @@
     return skip;
 }
 
-static void PreCallRecordCmdSetDepthBias(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_DEPTH_BIAS_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
-                                           float depthBiasSlopeFactor) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetDepthBias(dev_data, pCB, commandBuffer, depthBiasClamp);
-        if (!skip) {
-            PreCallRecordCmdSetDepthBias(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
-    }
+void CoreChecks::PreCallRecordCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
+                                              float depthBiasSlopeFactor) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_DEPTH_BIAS_SET;
 }
 
-static bool PreCallValidateCmdSetBlendConstants(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETBLENDCONSTANTS, "vkCmdSetBlendConstants()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETBLENDCONSTANTS, "vkCmdSetBlendConstants()");
     if (cb_state->static_status & CBSTATUS_BLEND_CONSTANTS_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetBlendConstants-None-00612",
                         "vkCmdSetBlendConstants(): pipeline was created without VK_DYNAMIC_STATE_BLEND_CONSTANTS flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetBlendConstants(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_BLEND_CONSTANTS_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetBlendConstants(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetBlendConstants(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
+void CoreChecks::PreCallRecordCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_BLEND_CONSTANTS_SET;
 }
 
-static bool PreCallValidateCmdSetDepthBounds(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETDEPTHBOUNDS, "vkCmdSetDepthBounds()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETDEPTHBOUNDS, "vkCmdSetDepthBounds()");
     if (cb_state->static_status & CBSTATUS_DEPTH_BOUNDS_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetDepthBounds-None-00599",
                         "vkCmdSetDepthBounds(): pipeline was created without VK_DYNAMIC_STATE_DEPTH_BOUNDS flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetDepthBounds(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_DEPTH_BOUNDS_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetDepthBounds(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetDepthBounds(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
+void CoreChecks::PreCallRecordCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_DEPTH_BOUNDS_SET;
 }
 
-static bool PreCallValidateCmdSetStencilCompareMask(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                         uint32_t compareMask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETSTENCILCOMPAREMASK, "vkCmdSetStencilCompareMask()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETSTENCILCOMPAREMASK, "vkCmdSetStencilCompareMask()");
     if (cb_state->static_status & CBSTATUS_STENCIL_READ_MASK_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetStencilCompareMask-None-00602",
                         "vkCmdSetStencilCompareMask(): pipeline was created without VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetStencilCompareMask(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_STENCIL_READ_MASK_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
-                                                    uint32_t compareMask) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetStencilCompareMask(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetStencilCompareMask(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
+void CoreChecks::PreCallRecordCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                       uint32_t compareMask) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_STENCIL_READ_MASK_SET;
 }
 
-static bool PreCallValidateCmdSetStencilWriteMask(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                       uint32_t writeMask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETSTENCILWRITEMASK, "vkCmdSetStencilWriteMask()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETSTENCILWRITEMASK, "vkCmdSetStencilWriteMask()");
     if (cb_state->static_status & CBSTATUS_STENCIL_WRITE_MASK_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetStencilWriteMask-None-00603",
                         "vkCmdSetStencilWriteMask(): pipeline was created without VK_DYNAMIC_STATE_STENCIL_WRITE_MASK flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetStencilWriteMask(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_STENCIL_WRITE_MASK_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetStencilWriteMask(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetStencilWriteMask(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
+void CoreChecks::PreCallRecordCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                     uint32_t writeMask) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
 }
 
-static bool PreCallValidateCmdSetStencilReference(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                       uint32_t reference) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdSetStencilReference-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETSTENCILREFERENCE, "vkCmdSetStencilReference()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETSTENCILREFERENCE, "vkCmdSetStencilReference()");
     if (cb_state->static_status & CBSTATUS_STENCIL_REFERENCE_SET) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetStencilReference-None-00604",
                         "vkCmdSetStencilReference(): pipeline was created without VK_DYNAMIC_STATE_STENCIL_REFERENCE flag..");
     }
     return skip;
 }
 
-static void PreCallRecordCmdSetStencilReference(GLOBAL_CB_NODE *cb_state) { cb_state->status |= CBSTATUS_STENCIL_REFERENCE_SET; }
-
-VKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetStencilReference(dev_data, pCB, commandBuffer);
-        if (!skip) {
-            PreCallRecordCmdSetStencilReference(pCB);
-        }
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
+void CoreChecks::PreCallRecordCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
+                                                     uint32_t reference) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->status |= CBSTATUS_STENCIL_REFERENCE_SET;
 }
 
 // Update pipeline_layout bind points applying the "Pipeline Layout Compatibility" rules
@@ -7082,7 +6885,10 @@
         cvdescriptorset::DescriptorSet *descriptor_set = descriptor_sets[input_idx];
 
         // Record binding (or push)
-        push_descriptor_cleanup(bound_sets[set_idx]);
+        if (descriptor_set != last_bound.push_descriptor_set.get()) {
+            // Only cleanup the push descriptors if they aren't the currently used set.
+            push_descriptor_cleanup(bound_sets[set_idx]);
+        }
         bound_sets[set_idx] = descriptor_set;
         bound_compat_ids[set_idx] = pipe_compat_ids[set_idx];  // compat ids are canonical *per* set index
 
@@ -7106,10 +6912,12 @@
 }
 
 // Update the bound state for the bind point, including the effects of incompatible pipeline layouts
-static void PreCallRecordCmdBindDescriptorSets(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
-                                               VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet,
-                                               uint32_t setCount, const VkDescriptorSet *pDescriptorSets,
-                                               uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) {
+void CoreChecks::PreCallRecordCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                    VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
+                                                    const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
+                                                    const uint32_t *pDynamicOffsets) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     auto pipeline_layout = GetPipelineLayout(device_data, layout);
     std::vector<cvdescriptorset::DescriptorSet *> descriptor_sets;
     descriptor_sets.reserve(setCount);
@@ -7117,7 +6925,7 @@
     // Construct a list of the descriptors
     bool found_non_null = false;
     for (uint32_t i = 0; i < setCount; i++) {
-        cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(device_data, pDescriptorSets[i]);
+        cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(pDescriptorSets[i]);
         descriptor_sets.emplace_back(descriptor_set);
         found_non_null |= descriptor_set != nullptr;
     }
@@ -7128,10 +6936,33 @@
     }
 }
 
-static bool PreCallValidateCmdBindDescriptorSets(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
-                                                 VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet,
-                                                 uint32_t setCount, const VkDescriptorSet *pDescriptorSets,
-                                                 uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) {
+static bool ValidateDynamicOffsetAlignment(const debug_report_data *report_data, const VkDescriptorSetLayoutBinding *binding,
+                                           VkDescriptorType test_type, VkDeviceSize alignment, const uint32_t *pDynamicOffsets,
+                                           const char *err_msg, const char *limit_name, uint32_t *offset_idx) {
+    bool skip = false;
+    if (binding->descriptorType == test_type) {
+        const auto end_idx = *offset_idx + binding->descriptorCount;
+        for (uint32_t current_idx = *offset_idx; current_idx < end_idx; current_idx++) {
+            if (SafeModulo(pDynamicOffsets[current_idx], alignment) != 0) {
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, err_msg,
+                    "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of device limit %s 0x%" PRIxLEAST64
+                    ".",
+                    current_idx, pDynamicOffsets[current_idx], limit_name, alignment);
+            }
+        }
+        *offset_idx = end_idx;
+    }
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                      VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
+                                                      const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
+                                                      const uint32_t *pDynamicOffsets) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
     bool skip = false;
     skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                   "VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool");
@@ -7148,68 +6979,50 @@
     }
     auto pipeline_layout = GetPipelineLayout(device_data, layout);
     for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
-        cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(device_data, pDescriptorSets[set_idx]);
+        cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(pDescriptorSets[set_idx]);
         if (descriptor_set) {
-            if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
-                skip |= log_msg(
-                    device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                    HandleToUint64(pDescriptorSets[set_idx]), kVUID_Core_DrawState_DescriptorSetNotUpdated,
-                    "Descriptor Set 0x%" PRIx64 " bound but it was never updated. You may want to either update it or not bind it.",
-                    HandleToUint64(pDescriptorSets[set_idx]));
-            }
             // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
             if (!VerifySetLayoutCompatibility(descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
-                skip |=
-                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                            HandleToUint64(pDescriptorSets[set_idx]), "VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358",
-                            "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout at index %u of "
-                            "pipelineLayout 0x%" PRIx64 " due to: %s.",
-                            set_idx, set_idx + firstSet, HandleToUint64(layout), error_string.c_str());
+                skip |= log_msg(
+                    device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                    HandleToUint64(pDescriptorSets[set_idx]), "VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358",
+                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout at index %u of "
+                    "pipelineLayout %s due to: %s.",
+                    set_idx, set_idx + firstSet, device_data->report_data->FormatHandle(layout).c_str(), error_string.c_str());
             }
 
             auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
-
             if (set_dynamic_descriptor_count) {
                 // First make sure we won't overstep bounds of pDynamicOffsets array
                 if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
-                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
-                                    kVUID_Core_DrawState_InvalidDynamicOffsetCount,
-                                    "descriptorSet #%u (0x%" PRIx64
-                                    ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets array. "
-                                    "There must be one dynamic offset for each dynamic descriptor being bound.",
-                                    set_idx, HandleToUint64(pDescriptorSets[set_idx]), descriptor_set->GetDynamicDescriptorCount(),
-                                    (dynamicOffsetCount - total_dynamic_descriptors));
+                    // Test/report this here, such that we don't run past the end of pDynamicOffsets in the else clause
+                    skip |= log_msg(
+                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                        HandleToUint64(pDescriptorSets[set_idx]), "VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359",
+                        "descriptorSet #%u (%s) requires %u dynamicOffsets, but only %u dynamicOffsets are left in "
+                        "pDynamicOffsets array. There must be one dynamic offset for each dynamic descriptor being bound.",
+                        set_idx, device_data->report_data->FormatHandle(pDescriptorSets[set_idx]).c_str(),
+                        descriptor_set->GetDynamicDescriptorCount(), (dynamicOffsetCount - total_dynamic_descriptors));
+                    // Set the number found to the maximum to prevent duplicate messages, or subsquent descriptor sets from
+                    // testing against the "short tail" we're skipping below.
+                    total_dynamic_descriptors = dynamicOffsetCount;
                 } else {  // Validate dynamic offsets and Dynamic Offset Minimums
                     uint32_t cur_dyn_offset = total_dynamic_descriptors;
-                    for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
-                        if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
-                            if (SafeModulo(pDynamicOffsets[cur_dyn_offset],
-                                           device_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) !=
-                                0) {
-                                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
-                                                "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
-                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
-                                                "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
-                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
-                                                device_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
-                            }
-                            cur_dyn_offset++;
-                        } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
-                            if (SafeModulo(pDynamicOffsets[cur_dyn_offset],
-                                           device_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) !=
-                                0) {
-                                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
-                                                "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
-                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
-                                                "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
-                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
-                                                device_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment);
-                            }
-                            cur_dyn_offset++;
-                        }
+                    const auto dsl = descriptor_set->GetLayout();
+                    const auto binding_count = dsl->GetBindingCount();
+                    const auto &limits = device_data->phys_dev_props.limits;
+                    for (uint32_t binding_idx = 0; binding_idx < binding_count; binding_idx++) {
+                        const auto *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
+                        skip |= ValidateDynamicOffsetAlignment(device_data->report_data, binding,
+                                                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+                                                               limits.minUniformBufferOffsetAlignment, pDynamicOffsets,
+                                                               "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
+                                                               "minUniformBufferOffsetAlignment", &cur_dyn_offset);
+                        skip |= ValidateDynamicOffsetAlignment(device_data->report_data, binding,
+                                                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+                                                               limits.minStorageBufferOffsetAlignment, pDynamicOffsets,
+                                                               "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
+                                                               "minStorageBufferOffsetAlignment", &cur_dyn_offset);
                     }
                     // Keep running total of dynamic descriptor count to verify at the end
                     total_dynamic_descriptors += set_dynamic_descriptor_count;
@@ -7218,8 +7031,8 @@
         } else {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                             HandleToUint64(pDescriptorSets[set_idx]), kVUID_Core_DrawState_InvalidSet,
-                            "Attempt to bind descriptor set 0x%" PRIx64 " that doesn't exist!",
-                            HandleToUint64(pDescriptorSets[set_idx]));
+                            "Attempt to bind descriptor set %s that doesn't exist!",
+                            device_data->report_data->FormatHandle(pDescriptorSets[set_idx]).c_str());
         }
     }
     //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
@@ -7233,61 +7046,42 @@
     return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
-                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
-                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
-                                                 const uint32_t *pDynamicOffsets) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
-    assert(cb_state);
-    skip = PreCallValidateCmdBindDescriptorSets(device_data, cb_state, pipelineBindPoint, layout, firstSet, setCount,
-                                                pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
-    if (!skip) {
-        PreCallRecordCmdBindDescriptorSets(device_data, cb_state, pipelineBindPoint, layout, firstSet, setCount, pDescriptorSets,
-                                           dynamicOffsetCount, pDynamicOffsets);
-        lock.unlock();
-        device_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
-                                                          pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
-    } else {
-        lock.unlock();
-    }
-}
-
 // Validates that the supplied bind point is supported for the command buffer (vis. the command pool)
 // Takes array of error codes as some of the VUID's (e.g. vkCmdBindPipeline) are written per bindpoint
 // TODO add vkCmdBindPipeline bind_point validation using this call.
-bool ValidatePipelineBindPoint(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                               const char *func_name, const std::map<VkPipelineBindPoint, std::string> &bind_errors) {
+bool CoreChecks::ValidatePipelineBindPoint(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
+                                           const char *func_name, const std::map<VkPipelineBindPoint, std::string> &bind_errors) {
     bool skip = false;
-    auto pool = GetCommandPoolNode(device_data, cb_state->createInfo.commandPool);
+    auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
     if (pool) {  // The loss of a pool in a recording cmd is reported in DestroyCommandPool
         static const std::map<VkPipelineBindPoint, VkQueueFlags> flag_mask = {
             std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT)),
             std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, static_cast<VkQueueFlags>(VK_QUEUE_COMPUTE_BIT)),
-            std::make_pair(VK_PIPELINE_BIND_POINT_RAYTRACING_NVX,
+            std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_NV,
                            static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)),
         };
-        const auto &qfp = GetPhysDevProperties(device_data)->queue_family_properties[pool->queueFamilyIndex];
+        const auto &qfp = GetPhysicalDeviceState()->queue_family_properties[pool->queueFamilyIndex];
         if (0 == (qfp.queueFlags & flag_mask.at(bind_point))) {
-            const std::string error = bind_errors.at(bind_point);
+            const std::string &error = bind_errors.at(bind_point);
             auto cb_u64 = HandleToUint64(cb_state->commandBuffer);
             auto cp_u64 = HandleToUint64(cb_state->createInfo.commandPool);
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             cb_u64, error,
-                            "%s: CommandBuffer 0x%" PRIxLEAST64 " was allocated from VkCommandPool 0x%" PRIxLEAST64
-                            " that does not support bindpoint %s.",
-                            func_name, cb_u64, cp_u64, string_VkPipelineBindPoint(bind_point));
+                            "%s: CommandBuffer %s was allocated from VkCommandPool %s that does not support bindpoint %s.",
+                            func_name, device_data->report_data->FormatHandle(cb_u64).c_str(),
+                            device_data->report_data->FormatHandle(cp_u64).c_str(), string_VkPipelineBindPoint(bind_point));
         }
     }
     return skip;
 }
 
-static bool PreCallValidateCmdPushDescriptorSetKHR(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
-                                                   const VkPipelineBindPoint bind_point, const VkPipelineLayout layout,
-                                                   const uint32_t set, const uint32_t descriptor_write_count,
-                                                   const VkWriteDescriptorSet *descriptor_writes, const char *func_name) {
+bool CoreChecks::PreCallValidateCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                        VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                                        const VkWriteDescriptorSet *pDescriptorWrites) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    const char *func_name = "vkCmdPushDescriptorSetKHR()";
     bool skip = false;
     skip |= ValidateCmd(device_data, cb_state, CMD_PUSHDESCRIPTORSETKHR, func_name);
     skip |= ValidateCmdQueueFlags(device_data, cb_state, func_name, (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT),
@@ -7296,9 +7090,9 @@
     static const std::map<VkPipelineBindPoint, std::string> bind_errors = {
         std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363"),
         std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363"),
-        std::make_pair(VK_PIPELINE_BIND_POINT_RAYTRACING_NVX, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363")};
+        std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363")};
 
-    skip |= ValidatePipelineBindPoint(device_data, cb_state, bind_point, func_name, bind_errors);
+    skip |= ValidatePipelineBindPoint(device_data, cb_state, pipelineBindPoint, func_name, bind_errors);
     auto layout_data = GetPipelineLayout(device_data, layout);
 
     // Validate the set index points to a push descriptor set and is in range
@@ -7306,55 +7100,67 @@
         const auto &set_layouts = layout_data->set_layouts;
         const auto layout_u64 = HandleToUint64(layout);
         if (set < set_layouts.size()) {
-            const auto *dsl = set_layouts[set].get();
-            if (dsl && (0 == (dsl->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR))) {
-                skip =
-                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00365",
-                            "%s: Set index %" PRIu32
-                            " does not match push descriptor set layout index for VkPipelineLayout 0x%" PRIxLEAST64 ".",
-                            func_name, set, layout_u64);
+            const auto dsl = set_layouts[set];
+            if (dsl) {
+                if (!dsl->IsPushDescriptor()) {
+                    skip = log_msg(
+                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
+                        layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00365",
+                        "%s: Set index %" PRIu32 " does not match push descriptor set layout index for VkPipelineLayout %s.",
+                        func_name, set, device_data->report_data->FormatHandle(layout_u64).c_str());
+                } else {
+                    // Create an empty proxy in order to use the existing descriptor set update validation
+                    // TODO move the validation (like this) that doesn't need descriptor set state to the DSL object so we
+                    // don't have to do this.
+                    cvdescriptorset::DescriptorSet proxy_ds(VK_NULL_HANDLE, VK_NULL_HANDLE, dsl, 0, device_data);
+                    skip |= proxy_ds.ValidatePushDescriptorsUpdate(device_data->report_data, descriptorWriteCount,
+                                                                   pDescriptorWrites, func_name);
+                }
             }
         } else {
-            skip = log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
-                           layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00364",
-                           "%s: Set index %" PRIu32 " is outside of range for VkPipelineLayout 0x%" PRIxLEAST64 " (set < %" PRIu32
-                           ").",
-                           func_name, set, layout_u64, static_cast<uint32_t>(set_layouts.size()));
+            skip =
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
+                        layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00364",
+                        "%s: Set index %" PRIu32 " is outside of range for VkPipelineLayout %s (set < %" PRIu32 ").", func_name,
+                        set, device_data->report_data->FormatHandle(layout_u64).c_str(), static_cast<uint32_t>(set_layouts.size()));
         }
     }
 
     return skip;
 }
-static void PreCallRecordCmdPushDescriptorSetKHR(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
+
+void CoreChecks::RecordCmdPushDescriptorSetState(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
                                                  VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set,
                                                  uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites) {
     const auto &pipeline_layout = GetPipelineLayout(device_data, layout);
-    if (!pipeline_layout) return;
-    std::unique_ptr<cvdescriptorset::DescriptorSet> new_desc{
-        new cvdescriptorset::DescriptorSet(0, 0, pipeline_layout->set_layouts[set], 0, device_data)};
+    // Short circuit invalid updates
+    if (!pipeline_layout || (set >= pipeline_layout->set_layouts.size()) || !pipeline_layout->set_layouts[set] ||
+        !pipeline_layout->set_layouts[set]->IsPushDescriptor())
+        return;
 
-    std::vector<cvdescriptorset::DescriptorSet *> descriptor_sets = {new_desc.get()};
+    // We need a descriptor set to update the bindings with, compatible with the passed layout
+    const auto dsl = pipeline_layout->set_layouts[set];
+    auto &last_bound = cb_state->lastBound[pipelineBindPoint];
+    auto &push_descriptor_set = last_bound.push_descriptor_set;
+    // If we are disturbing the current push_desriptor_set clear it
+    if (!push_descriptor_set || !CompatForSet(set, last_bound.compat_id_for_set, pipeline_layout->compat_for_set)) {
+        push_descriptor_set.reset(new cvdescriptorset::DescriptorSet(0, 0, dsl, 0, device_data));
+    }
+
+    std::vector<cvdescriptorset::DescriptorSet *> descriptor_sets = {push_descriptor_set.get()};
     UpdateLastBoundDescriptorSets(device_data, cb_state, pipelineBindPoint, pipeline_layout, set, 1, descriptor_sets, 0, nullptr);
-    cb_state->lastBound[pipelineBindPoint].push_descriptor_set = std::move(new_desc);
-    cb_state->lastBound[pipelineBindPoint].pipeline_layout = layout;
+    last_bound.pipeline_layout = layout;
+
+    // Now that we have either the new or extant push_descriptor set ... do the write updates against it
+    push_descriptor_set->PerformPushDescriptorsUpdate(descriptorWriteCount, pDescriptorWrites);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
-                                                   VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
-                                                   const VkWriteDescriptorSet *pDescriptorWrites) {
+void CoreChecks::PreCallRecordCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                      VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                                      const VkWriteDescriptorSet *pDescriptorWrites) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto cb_state = GetCBNode(device_data, commandBuffer);
-    bool skip = PreCallValidateCmdPushDescriptorSetKHR(device_data, cb_state, pipelineBindPoint, layout, set, descriptorWriteCount,
-                                                       pDescriptorWrites, "vkCmdPushDescriptorSetKHR()");
-    if (!skip) {
-        PreCallRecordCmdPushDescriptorSetKHR(device_data, cb_state, pipelineBindPoint, layout, set, descriptorWriteCount,
-                                             pDescriptorWrites);
-        lock.unlock();
-        device_data->dispatch_table.CmdPushDescriptorSetKHR(commandBuffer, pipelineBindPoint, layout, set, descriptorWriteCount,
-                                                            pDescriptorWrites);
-    }
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    RecordCmdPushDescriptorSetState(device_data, cb_state, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites);
 }
 
 static VkDeviceSize GetIndexAlignment(VkIndexType indexType) {
@@ -7370,20 +7176,25 @@
     }
 }
 
-static bool PreCallValidateCmdBindIndexBuffer(layer_data *dev_data, BUFFER_STATE *buffer_state, GLOBAL_CB_NODE *cb_node,
-                                              VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                              VkIndexType indexType) {
-    bool skip = ValidateBufferUsageFlags(dev_data, buffer_state, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, true,
+bool CoreChecks::PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                   VkIndexType indexType) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto buffer_state = GetBufferState(buffer);
+    auto cb_node = GetCBNode(commandBuffer);
+    assert(buffer_state);
+    assert(cb_node);
+
+    bool skip = ValidateBufferUsageFlags(device_data, buffer_state, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, true,
                                          "VUID-vkCmdBindIndexBuffer-buffer-00433", "vkCmdBindIndexBuffer()",
                                          "VK_BUFFER_USAGE_INDEX_BUFFER_BIT");
-    skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT,
+    skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT,
                                   "VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
-    skip |=
-        ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", "VUID-vkCmdBindIndexBuffer-buffer-00434");
+    skip |= ValidateCmd(device_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdBindIndexBuffer()",
+                                          "VUID-vkCmdBindIndexBuffer-buffer-00434");
     auto offset_align = GetIndexAlignment(indexType);
     if (offset % offset_align) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdBindIndexBuffer-offset-00432",
                         "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
                         string_VkIndexType(indexType));
@@ -7392,8 +7203,11 @@
     return skip;
 }
 
-static void PreCallRecordCmdBindIndexBuffer(BUFFER_STATE *buffer_state, GLOBAL_CB_NODE *cb_node, VkBuffer buffer,
-                                            VkDeviceSize offset, VkIndexType indexType) {
+void CoreChecks::PreCallRecordCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                 VkIndexType indexType) {
+    auto buffer_state = GetBufferState(buffer);
+    auto cb_node = GetCBNode(commandBuffer);
+
     cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
     cb_node->index_buffer_binding.buffer = buffer;
     cb_node->index_buffer_binding.size = buffer_state->createInfo.size;
@@ -7401,44 +7215,27 @@
     cb_node->index_buffer_binding.index_type = indexType;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                              VkIndexType indexType) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto buffer_state = GetBufferState(dev_data, buffer);
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    assert(cb_node);
-    assert(buffer_state);
-
-    PreCallValidateCmdBindIndexBuffer(dev_data, buffer_state, cb_node, commandBuffer, buffer, offset, indexType);
-
-    if (skip) return;
-
-    PreCallRecordCmdBindIndexBuffer(buffer_state, cb_node, buffer, offset, indexType);
-    lock.unlock();
-
-    dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
-}
-
 static inline void UpdateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->draw_data.push_back(pCB->current_draw_data); }
 
-static bool PreCallValidateCmdBindVertexBuffers(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, uint32_t bindingCount,
-                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT,
+bool CoreChecks::PreCallValidateCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
+                                                     const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT,
                                       "VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_BINDVERTEXBUFFERS, "vkCmdBindVertexBuffers()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_BINDVERTEXBUFFERS, "vkCmdBindVertexBuffers()");
     for (uint32_t i = 0; i < bindingCount; ++i) {
-        auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
+        auto buffer_state = GetBufferState(pBuffers[i]);
         assert(buffer_state);
-        skip |= ValidateBufferUsageFlags(dev_data, buffer_state, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, true,
+        skip |= ValidateBufferUsageFlags(device_data, buffer_state, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, true,
                                          "VUID-vkCmdBindVertexBuffers-pBuffers-00627", "vkCmdBindVertexBuffers()",
                                          "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT");
-        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()",
+        skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdBindVertexBuffers()",
                                               "VUID-vkCmdBindVertexBuffers-pBuffers-00628");
         if (pOffsets[i] >= buffer_state->createInfo.size) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                             HandleToUint64(buffer_state->buffer), "VUID-vkCmdBindVertexBuffers-pOffsets-00626",
                             "vkCmdBindVertexBuffers() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer.", pOffsets[i]);
         }
@@ -7446,106 +7243,84 @@
     return skip;
 }
 
-static void PreCallRecordCmdBindVertexBuffers(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount,
-                                              const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
+void CoreChecks::PreCallRecordCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
+                                                   const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
+    auto cb_state = GetCBNode(commandBuffer);
+
     uint32_t end = firstBinding + bindingCount;
-    if (pCB->current_draw_data.vertex_buffer_bindings.size() < end) {
-        pCB->current_draw_data.vertex_buffer_bindings.resize(end);
+    if (cb_state->current_draw_data.vertex_buffer_bindings.size() < end) {
+        cb_state->current_draw_data.vertex_buffer_bindings.resize(end);
     }
 
     for (uint32_t i = 0; i < bindingCount; ++i) {
-        auto &vertex_buffer_binding = pCB->current_draw_data.vertex_buffer_bindings[i + firstBinding];
+        auto &vertex_buffer_binding = cb_state->current_draw_data.vertex_buffer_bindings[i + firstBinding];
         vertex_buffer_binding.buffer = pBuffers[i];
         vertex_buffer_binding.offset = pOffsets[i];
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
-                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    assert(cb_node);
-
-    skip |= PreCallValidateCmdBindVertexBuffers(dev_data, cb_node, bindingCount, pBuffers, pOffsets);
-
-    if (skip) return;
-
-    PreCallRecordCmdBindVertexBuffers(cb_node, firstBinding, bindingCount, pBuffers, pOffsets);
-
-    lock.unlock();
-    dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
-}
-
 // Generic function to handle validation for all CmdDraw* type functions
-static bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
-                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
-                                const std::string &queue_flag_code, const std::string &renderpass_msg_code,
-                                const std::string &pipebound_msg_code, const std::string &dynamic_state_msg_code) {
+bool CoreChecks::ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
+                                     CMD_TYPE cmd_type, const char *caller, VkQueueFlags queue_flags, const char *queue_flag_code,
+                                     const char *renderpass_msg_code, const char *pipebound_msg_code,
+                                     const char *dynamic_state_msg_code) {
     bool skip = false;
-    *cb_state = GetCBNode(dev_data, cmd_buffer);
-    if (*cb_state) {
-        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
-        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
-        skip |= ValidateCmdBufDrawState(dev_data, *cb_state, cmd_type, indexed, bind_point, caller, pipebound_msg_code,
+    GLOBAL_CB_NODE *cb_state = GetCBNode(cmd_buffer);
+    if (cb_state) {
+        skip |= ValidateCmdQueueFlags(dev_data, cb_state, caller, queue_flags, queue_flag_code);
+        skip |= ValidateCmd(dev_data, cb_state, cmd_type, caller);
+        skip |= ValidateCmdBufDrawState(dev_data, cb_state, cmd_type, indexed, bind_point, caller, pipebound_msg_code,
                                         dynamic_state_msg_code);
-        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
-                    ? OutsideRenderPass(dev_data, *cb_state, caller, renderpass_msg_code)
-                    : InsideRenderPass(dev_data, *cb_state, caller, renderpass_msg_code);
+        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? OutsideRenderPass(dev_data, cb_state, caller, renderpass_msg_code)
+                                                                : InsideRenderPass(dev_data, cb_state, caller, renderpass_msg_code);
     }
     return skip;
 }
 
 // Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
-static void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
+void CoreChecks::UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
     UpdateDrawState(dev_data, cb_state, bind_point);
 }
 
 // Generic function to handle state update for all CmdDraw* type functions
-static void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
+void CoreChecks::UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
     UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point);
     UpdateResourceTrackingOnDraw(cb_state);
     cb_state->hasDrawCmd = true;
 }
 
-static bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
-                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
-    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
-                               "VUID-vkCmdDraw-commandBuffer-cmdpool", "VUID-vkCmdDraw-renderpass", "VUID-vkCmdDraw-None-00442",
-                               "VUID-vkCmdDraw-None-00443");
+bool CoreChecks::PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
+                                        uint32_t firstVertex, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    return ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAW, "vkCmdDraw()",
+                               VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDraw-commandBuffer-cmdpool", "VUID-vkCmdDraw-renderpass",
+                               "VUID-vkCmdDraw-None-00442", "VUID-vkCmdDraw-None-00443");
 }
 
-static void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
+                                      uint32_t firstVertex, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
-                                   uint32_t firstVertex, uint32_t firstInstance) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
-        lock.lock();
-        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
-        lock.unlock();
-    }
+void CoreChecks::PostCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
+                                       uint32_t firstVertex, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-static bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
-                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller,
-                                          uint32_t indexCount, uint32_t firstIndex) {
-    bool skip =
-        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
-                            "VUID-vkCmdDrawIndexed-commandBuffer-cmdpool", "VUID-vkCmdDrawIndexed-renderpass",
-                            "VUID-vkCmdDrawIndexed-None-00461", "VUID-vkCmdDrawIndexed-None-00462");
-    if (!skip && ((*cb_state)->status & CBSTATUS_INDEX_BUFFER_BOUND)) {
+bool CoreChecks::PreCallValidateCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                               uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdDrawType(device_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWINDEXED,
+                                    "vkCmdDrawIndexed()", VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndexed-commandBuffer-cmdpool",
+                                    "VUID-vkCmdDrawIndexed-renderpass", "VUID-vkCmdDrawIndexed-None-00461",
+                                    "VUID-vkCmdDrawIndexed-None-00462");
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    if (!skip && (cb_state->status & CBSTATUS_INDEX_BUFFER_BOUND)) {
         unsigned int index_size = 0;
-        const auto &index_buffer_binding = (*cb_state)->index_buffer_binding;
+        const auto &index_buffer_binding = cb_state->index_buffer_binding;
         if (index_buffer_binding.index_type == VK_INDEX_TYPE_UINT16) {
             index_size = 2;
         } else if (index_buffer_binding.index_type == VK_INDEX_TYPE_UINT32) {
@@ -7553,7 +7328,7 @@
         }
         VkDeviceSize end_offset = (index_size * ((VkDeviceSize)firstIndex + indexCount)) + index_buffer_binding.offset;
         if (end_offset > index_buffer_binding.size) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
                             HandleToUint64(index_buffer_binding.buffer), "VUID-vkCmdDrawIndexed-indexSize-00463",
                             "vkCmdDrawIndexed() index size (%d) * (firstIndex (%d) + indexCount (%d)) "
                             "+ binding offset (%" PRIuLEAST64 ") = an ending offset of %" PRIuLEAST64
@@ -7565,296 +7340,144 @@
     return skip;
 }
 
-static void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                             uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
-                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
-                                              "vkCmdDrawIndexed()", indexCount, firstIndex);
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
-        lock.lock();
-        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
-        lock.unlock();
-    }
+void CoreChecks::PostCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                              uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-static bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
-                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
-                                           const char *caller) {
-    bool skip =
-        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
-                            "VUID-vkCmdDrawIndirect-commandBuffer-cmdpool", "VUID-vkCmdDrawIndirect-renderpass",
-                            "VUID-vkCmdDrawIndirect-None-00485", "VUID-vkCmdDrawIndirect-None-00486");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawIndirect-buffer-00474");
+bool CoreChecks::PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                                uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWINDIRECT,
+                                    "vkCmdDrawIndirect()", VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndirect-commandBuffer-cmdpool",
+                                    "VUID-vkCmdDrawIndirect-renderpass", "VUID-vkCmdDrawIndirect-None-00485",
+                                    "VUID-vkCmdDrawIndirect-None-00486");
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawIndirect()", "VUID-vkCmdDrawIndirect-buffer-00474");
     // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
     // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
     return skip;
 }
 
-static void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                                          BUFFER_STATE *buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
+void CoreChecks::PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                              uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
-                                           uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
-                                               &buffer_state, "vkCmdDrawIndirect()");
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
-        lock.lock();
-        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
-        lock.unlock();
-    }
+void CoreChecks::PostCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                               uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
+    AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
 }
 
-static bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
-                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
-                                                  BUFFER_STATE **buffer_state, const char *caller) {
-    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
-                                    VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndexedIndirect-commandBuffer-cmdpool",
-                                    "VUID-vkCmdDrawIndexedIndirect-renderpass", "VUID-vkCmdDrawIndexedIndirect-None-00537",
-                                    "VUID-vkCmdDrawIndexedIndirect-None-00538");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawIndexedIndirect-buffer-00526");
+bool CoreChecks::PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                       uint32_t count, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdDrawType(
+        device_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()",
+        VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndexedIndirect-commandBuffer-cmdpool", "VUID-vkCmdDrawIndexedIndirect-renderpass",
+        "VUID-vkCmdDrawIndexedIndirect-None-00537", "VUID-vkCmdDrawIndexedIndirect-None-00538");
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawIndexedIndirect()",
+                                          "VUID-vkCmdDrawIndexedIndirect-buffer-00526");
     // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
     // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
     // 'buffer'.
     return skip;
 }
 
-static void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                                                 BUFFER_STATE *buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
+void CoreChecks::PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                     uint32_t count, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                                  uint32_t count, uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
-        lock.lock();
-        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
-        lock.unlock();
-    }
+void CoreChecks::PostCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                      uint32_t count, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
+    AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
 }
 
-static bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
-                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
-    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
-                               "VUID-vkCmdDispatch-commandBuffer-cmdpool", "VUID-vkCmdDispatch-renderpass",
+bool CoreChecks::PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    return ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, CMD_DISPATCH, "vkCmdDispatch()",
+                               VK_QUEUE_COMPUTE_BIT, "VUID-vkCmdDispatch-commandBuffer-cmdpool", "VUID-vkCmdDispatch-renderpass",
                                "VUID-vkCmdDispatch-None-00391", kVUIDUndefined);
 }
 
-static void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
-    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip =
-        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
-        lock.lock();
-        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
-        lock.unlock();
-    }
+void CoreChecks::PostCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawDispatchType(device_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
 }
 
-static bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
-                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
-                                               BUFFER_STATE **buffer_state, const char *caller) {
+bool CoreChecks::PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip =
-        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
-                            "VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool", "VUID-vkCmdDispatchIndirect-renderpass",
-                            "VUID-vkCmdDispatchIndirect-None-00404", kVUIDUndefined);
-    *buffer_state = GetBufferState(dev_data, buffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDispatchIndirect-buffer-00401");
+        ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, CMD_DISPATCHINDIRECT,
+                            "vkCmdDispatchIndirect()", VK_QUEUE_COMPUTE_BIT, "VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool",
+                            "VUID-vkCmdDispatchIndirect-renderpass", "VUID-vkCmdDispatchIndirect-None-00404", kVUIDUndefined);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDispatchIndirect()",
+                                          "VUID-vkCmdDispatchIndirect-buffer-00401");
     return skip;
 }
 
-static void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                                              BUFFER_STATE *buffer_state) {
-    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
-                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
-        lock.lock();
-        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
-        lock.unlock();
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
-                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
+void CoreChecks::PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
-    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
-
-    if (cb_node && src_buffer_state && dst_buffer_state) {
-        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
-        if (!skip) {
-            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
-            lock.unlock();
-            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
-        }
-    } else {
-        lock.unlock();
-        assert(0);
-    }
+    GpuAllocateValidationResources(device_data, commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
-                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
-                                        const VkImageCopy *pRegions) {
-    bool skip = false;
+void CoreChecks::PostCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto src_image_state = GetImageState(device_data, srcImage);
-    auto dst_image_state = GetImageState(device_data, dstImage);
-    if (cb_node && src_image_state && dst_image_state) {
-        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
-                                           srcImageLayout, dstImageLayout);
-        if (!skip) {
-            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
-                                      dstImageLayout);
-            lock.unlock();
-            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
-                                                     pRegions);
-        }
-    } else {
-        lock.unlock();
-        assert(0);
-    }
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawDispatchType(device_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
 }
 
 // Validate that an image's sampleCount matches the requirement for a specific API call
-bool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
-                              const char *location, const std::string &msgCode) {
+bool CoreChecks::ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
+                                          const char *location, const std::string &msgCode) {
     bool skip = false;
     if (image_state->createInfo.samples != sample_count) {
         skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                        HandleToUint64(image_state->image), msgCode,
-                       "%s for image 0x%" PRIx64 " was created with a sample count of %s but must be %s.", location,
-                       HandleToUint64(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
-                       string_VkSampleCountFlagBits(sample_count));
+                       "%s for image %s was created with a sample count of %s but must be %s.", location,
+                       dev_data->report_data->FormatHandle(image_state->image).c_str(),
+                       string_VkSampleCountFlagBits(image_state->createInfo.samples), string_VkSampleCountFlagBits(sample_count));
     }
     return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
-                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
-                                        const VkImageBlit *pRegions, VkFilter filter) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    auto src_image_state = GetImageState(dev_data, srcImage);
-    auto dst_image_state = GetImageState(dev_data, dstImage);
-
-    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
-                                            srcImageLayout, dstImageLayout, filter);
-
-    if (!skip) {
-        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
-                                  dstImageLayout);
-        lock.unlock();
-        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
-                                              pRegions, filter);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
-                                                VkImageLayout dstImageLayout, uint32_t regionCount,
-                                                const VkBufferImageCopy *pRegions) {
+bool CoreChecks::PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                                VkDeviceSize dataSize, const void *pData) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = false;
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
-    auto dst_image_state = GetImageState(device_data, dstImage);
-    if (cb_node && src_buffer_state && dst_image_state) {
-        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
-                                                   regionCount, pRegions, "vkCmdCopyBufferToImage()");
-    } else {
-        lock.unlock();
-        assert(0);
-        // TODO: report VU01244 here, or put in object tracker?
-    }
-    if (!skip) {
-        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
-                                          dstImageLayout);
-        lock.unlock();
-        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
-    }
-}
+    auto cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+    assert(dst_buffer_state);
 
-VKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
-                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto src_image_state = GetImageState(device_data, srcImage);
-    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
-    if (cb_node && src_image_state && dst_buffer_state) {
-        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
-                                                   regionCount, pRegions, "vkCmdCopyImageToBuffer()");
-    } else {
-        lock.unlock();
-        assert(0);
-        // TODO: report VU01262 here, or put in object tracker?
-    }
-    if (!skip) {
-        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
-                                          srcImageLayout);
-        lock.unlock();
-        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
-    }
-}
-
-static bool PreCallCmdUpdateBuffer(layer_data *device_data, const GLOBAL_CB_NODE *cb_state, const BUFFER_STATE *dst_buffer_state) {
     bool skip = false;
     skip |= ValidateMemoryIsBoundToBuffer(device_data, dst_buffer_state, "vkCmdUpdateBuffer()",
                                           "VUID-vkCmdUpdateBuffer-dstBuffer-00035");
@@ -7870,127 +7493,19 @@
     return skip;
 }
 
-static void PostCallRecordCmdUpdateBuffer(layer_data *device_data, GLOBAL_CB_NODE *cb_state, BUFFER_STATE *dst_buffer_state) {
+void CoreChecks::PostCallRecordCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                               VkDeviceSize dataSize, const void *pData) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_state = GetCBNode(commandBuffer);
+    auto dst_buffer_state = GetBufferState(dstBuffer);
+
     // Update bindings between buffer and cmd buffer
     AddCommandBufferBindingBuffer(device_data, cb_state, dst_buffer_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
-                                           VkDeviceSize dataSize, const uint32_t *pData) {
-    bool skip = false;
+bool CoreChecks::SetEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_state = GetCBNode(dev_data, commandBuffer);
-    assert(cb_state);
-    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
-    assert(dst_buff_state);
-    skip |= PreCallCmdUpdateBuffer(dev_data, cb_state, dst_buff_state);
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
-        lock.lock();
-        PostCallRecordCmdUpdateBuffer(dev_data, cb_state, dst_buff_state);
-        lock.unlock();
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
-                                         VkDeviceSize size, uint32_t data) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto cb_node = GetCBNode(device_data, commandBuffer);
-    auto buffer_state = GetBufferState(device_data, dstBuffer);
-
-    if (cb_node && buffer_state) {
-        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
-        if (!skip) {
-            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
-            lock.unlock();
-            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
-        }
-    } else {
-        lock.unlock();
-        assert(0);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
-                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
-                                               const VkClearRect *pRects) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    {
-        lock_guard_t lock(global_lock);
-        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
-    }
-    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
-                                              const VkClearColorValue *pColor, uint32_t rangeCount,
-                                              const VkImageSubresourceRange *pRanges) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
-    if (!skip) {
-        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
-        lock.unlock();
-        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
-                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
-                                                     const VkImageSubresourceRange *pRanges) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
-    if (!skip) {
-        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
-        lock.unlock();
-        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
-                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
-                                           const VkImageResolve *pRegions) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    auto src_image_state = GetImageState(dev_data, srcImage);
-    auto dst_image_state = GetImageState(dev_data, dstImage);
-
-    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, srcImageLayout, dst_image_state, dstImageLayout,
-                                               regionCount, pRegions);
-
-    if (!skip) {
-        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
-        lock.unlock();
-        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
-                                                 pRegions);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
-                                                     VkSubresourceLayout *pLayout) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
-    if (!skip) {
-        lock.unlock();
-        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
-    }
-}
-
-bool SetEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
+    GLOBAL_CB_NODE *pCB = GetCBNode(commandBuffer);
     if (pCB) {
         pCB->eventToStageMap[event] = stageMask;
     }
@@ -8001,20 +7516,23 @@
     return false;
 }
 
-static bool PreCallValidateCmdSetEvent(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineStageFlags stageMask) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+bool CoreChecks::PreCallValidateCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                       "VUID-vkCmdSetEvent-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_SETEVENT, "vkCmdSetEvent()");
-    skip |= InsideRenderPass(dev_data, cb_state, "vkCmdSetEvent()", "VUID-vkCmdSetEvent-renderpass");
-    skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", "VUID-vkCmdSetEvent-stageMask-01150",
+    skip |= ValidateCmd(device_data, cb_state, CMD_SETEVENT, "vkCmdSetEvent()");
+    skip |= InsideRenderPass(device_data, cb_state, "vkCmdSetEvent()", "VUID-vkCmdSetEvent-renderpass");
+    skip |= ValidateStageMaskGsTsEnables(device_data, stageMask, "vkCmdSetEvent()", "VUID-vkCmdSetEvent-stageMask-01150",
                                          "VUID-vkCmdSetEvent-stageMask-01151", "VUID-vkCmdSetEvent-stageMask-02107",
                                          "VUID-vkCmdSetEvent-stageMask-02108");
     return skip;
 }
 
-static void PreCallRecordCmdSetEvent(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer, VkEvent event,
-                                     VkPipelineStageFlags stageMask) {
-    auto event_state = GetEventNode(dev_data, event);
+void CoreChecks::PreCallRecordCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    auto event_state = GetEventNode(event);
     if (event_state) {
         AddCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, cb_state);
         event_state->cb_bindings.insert(cb_state);
@@ -8026,33 +7544,24 @@
     cb_state->eventUpdates.emplace_back([=](VkQueue q) { return SetEventStageMask(q, commandBuffer, event, stageMask); });
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdSetEvent(dev_data, pCB, stageMask);
-        PreCallRecordCmdSetEvent(dev_data, pCB, commandBuffer, event, stageMask);
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
-}
+bool CoreChecks::PreCallValidateCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
 
-static bool PreCallValidateCmdResetEvent(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineStageFlags stageMask) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                       "VUID-vkCmdResetEvent-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_RESETEVENT, "vkCmdResetEvent()");
-    skip |= InsideRenderPass(dev_data, cb_state, "vkCmdResetEvent()", "VUID-vkCmdResetEvent-renderpass");
-    skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", "VUID-vkCmdResetEvent-stageMask-01154",
+    skip |= ValidateCmd(device_data, cb_state, CMD_RESETEVENT, "vkCmdResetEvent()");
+    skip |= InsideRenderPass(device_data, cb_state, "vkCmdResetEvent()", "VUID-vkCmdResetEvent-renderpass");
+    skip |= ValidateStageMaskGsTsEnables(device_data, stageMask, "vkCmdResetEvent()", "VUID-vkCmdResetEvent-stageMask-01154",
                                          "VUID-vkCmdResetEvent-stageMask-01155", "VUID-vkCmdResetEvent-stageMask-02109",
                                          "VUID-vkCmdResetEvent-stageMask-02110");
     return skip;
 }
 
-static void PreCallRecordCmdResetEvent(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                       VkEvent event) {
-    auto event_state = GetEventNode(dev_data, event);
+void CoreChecks::PreCallRecordCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    auto event_state = GetEventNode(event);
     if (event_state) {
         AddCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, cb_state);
         event_state->cb_bindings.insert(cb_state);
@@ -8066,31 +7575,22 @@
         [=](VkQueue q) { return SetEventStageMask(q, commandBuffer, event, VkPipelineStageFlags(0)); });
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdResetEvent(dev_data, pCB, stageMask);
-        PreCallRecordCmdResetEvent(dev_data, pCB, commandBuffer, event);
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
-}
-
 // Return input pipeline stage flags, expanded for individual bits if VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT is set
-static VkPipelineStageFlags ExpandPipelineStageFlags(VkPipelineStageFlags inflags) {
+static VkPipelineStageFlags ExpandPipelineStageFlags(const DeviceExtensions &extensions, VkPipelineStageFlags inflags) {
     if (~inflags & VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT) return inflags;
 
     return (inflags & ~VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT) |
-           (VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
-            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
-            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
-            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
-            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
-            VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV |
-            VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV);
+           (VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
+            (extensions.vk_nv_mesh_shader ? (VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV) : 0) |
+            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
+            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
+            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
+            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
+            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT |
+            (extensions.vk_ext_conditional_rendering ? VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT : 0) |
+            (extensions.vk_ext_transform_feedback ? VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT : 0) |
+            (extensions.vk_nv_shading_rate_image ? VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV : 0) |
+            (extensions.vk_ext_fragment_density_map ? VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT : 0));
 }
 
 static bool HasNonFramebufferStagePipelineStageFlags(VkPipelineStageFlags inflags) {
@@ -8099,18 +7599,35 @@
 }
 
 static int GetGraphicsPipelineStageLogicalOrdinal(VkPipelineStageFlagBits flag) {
+    // Note that the list (and lookup) ignore invalid-for-enabled-extension condition.  This should be checked elsewhere
+    // and would greatly complicate this intentionally simple implementation
+    // clang-format off
     const VkPipelineStageFlagBits ordered_array[] = {
-        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
-        VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
-        VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
+        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+        VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
+        VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
+        VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
+        VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
+        VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
+        VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
+        VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
+
         // Including the task/mesh shaders here is not technically correct, as they are in a
         // separate logical pipeline - but it works for the case this is currently used, and
         // fixing it would require significant rework and end up with the code being far more
         // verbose for no practical gain.
         // However, worth paying attention to this if using this function in a new way.
-        VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
-        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
-        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT};
+        VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
+        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
+
+        VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV,
+        VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
+        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+        VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+        VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
+    };
+    // clang-format on
 
     const int ordered_array_length = sizeof(ordered_array) / sizeof(VkPipelineStageFlagBits);
 
@@ -8131,7 +7648,7 @@
     VkPipelineStageFlagBits earliest_bit = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
     int earliest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(earliest_bit);
 
-    for (int i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) {
+    for (std::size_t i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) {
         VkPipelineStageFlagBits current_flag = (VkPipelineStageFlagBits)((inflags & 0x1u) << i);
         if (current_flag) {
             int new_order = GetGraphicsPipelineStageLogicalOrdinal(current_flag);
@@ -8149,7 +7666,7 @@
     VkPipelineStageFlagBits latest_bit = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
     int latest_bit_order = GetGraphicsPipelineStageLogicalOrdinal(latest_bit);
 
-    for (int i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) {
+    for (std::size_t i = 0; i < sizeof(VkPipelineStageFlagBits); ++i) {
         if (inflags & 0x1u) {
             int new_order = GetGraphicsPipelineStageLogicalOrdinal((VkPipelineStageFlagBits)((inflags & 0x1u) << i));
             if (new_order != -1 && new_order > latest_bit_order) {
@@ -8163,12 +7680,12 @@
 }
 
 // Verify image barrier image state and that the image is consistent with FB image
-static bool ValidateImageBarrierImage(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE const *cb_state,
-                                      VkFramebuffer framebuffer, uint32_t active_subpass,
-                                      const safe_VkSubpassDescription2KHR &sub_desc, uint64_t rp_handle, uint32_t img_index,
-                                      const VkImageMemoryBarrier &img_barrier) {
+bool CoreChecks::ValidateImageBarrierImage(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE const *cb_state,
+                                           VkFramebuffer framebuffer, uint32_t active_subpass,
+                                           const safe_VkSubpassDescription2KHR &sub_desc, uint64_t rp_handle, uint32_t img_index,
+                                           const VkImageMemoryBarrier &img_barrier) {
     bool skip = false;
-    const auto &fb_state = GetFramebufferState(device_data, framebuffer);
+    const auto &fb_state = GetFramebufferState(framebuffer);
     assert(fb_state);
     const auto img_bar_image = img_barrier.image;
     bool image_match = false;
@@ -8178,7 +7695,7 @@
     // Verify that a framebuffer image matches barrier image
     const auto attachmentCount = fb_state->createInfo.attachmentCount;
     for (uint32_t attachment = 0; attachment < attachmentCount; ++attachment) {
-        auto view_state = GetAttachmentImageViewState(device_data, fb_state, attachment);
+        auto view_state = GetAttachmentImageViewState(fb_state, attachment);
         if (view_state && (img_bar_image == view_state->create_info.image)) {
             image_match = true;
             attach_index = attachment;
@@ -8189,6 +7706,13 @@
         if (sub_desc.pDepthStencilAttachment && sub_desc.pDepthStencilAttachment->attachment == attach_index) {
             sub_image_layout = sub_desc.pDepthStencilAttachment->layout;
             sub_image_found = true;
+        } else if (GetDeviceExtensions()->vk_khr_depth_stencil_resolve) {
+            const auto *resolve = lvl_find_in_chain<VkSubpassDescriptionDepthStencilResolveKHR>(sub_desc.pNext);
+            if (resolve && resolve->pDepthStencilResolveAttachment &&
+                resolve->pDepthStencilResolveAttachment->attachment == attach_index) {
+                sub_image_layout = resolve->pDepthStencilResolveAttachment->layout;
+                sub_image_found = true;
+            }
         } else {
             for (uint32_t j = 0; j < sub_desc.colorAttachmentCount; ++j) {
                 if (sub_desc.pColorAttachments && sub_desc.pColorAttachments[j].attachment == attach_index) {
@@ -8203,48 +7727,49 @@
             }
         }
         if (!sub_image_found) {
-            skip |= log_msg(
-                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
-                "VUID-vkCmdPipelineBarrier-image-01179",
-                "%s: Barrier pImageMemoryBarriers[%d].image (0x%" PRIx64
-                ") is not referenced by the VkSubpassDescription for active subpass (%d) of current renderPass (0x%" PRIx64 ").",
-                funcName, img_index, HandleToUint64(img_bar_image), active_subpass, rp_handle);
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
+                            rp_handle, "VUID-vkCmdPipelineBarrier-image-02635",
+                            "%s: Barrier pImageMemoryBarriers[%d].image (%s) is not referenced by the VkSubpassDescription for "
+                            "active subpass (%d) of current renderPass (%s).",
+                            funcName, img_index, device_data->report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
+                            device_data->report_data->FormatHandle(rp_handle).c_str());
         }
     } else {  // !image_match
         auto const fb_handle = HandleToUint64(fb_state->framebuffer);
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
-                        fb_handle, "VUID-vkCmdPipelineBarrier-image-01179",
-                        "%s: Barrier pImageMemoryBarriers[%d].image (0x%" PRIx64
-                        ") does not match an image from the current framebuffer (0x%" PRIx64 ").",
-                        funcName, img_index, HandleToUint64(img_bar_image), fb_handle);
+        skip |=
+            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT, fb_handle,
+                    "VUID-vkCmdPipelineBarrier-image-02635",
+                    "%s: Barrier pImageMemoryBarriers[%d].image (%s) does not match an image from the current framebuffer (%s).",
+                    funcName, img_index, device_data->report_data->FormatHandle(img_bar_image).c_str(),
+                    device_data->report_data->FormatHandle(fb_handle).c_str());
     }
     if (img_barrier.oldLayout != img_barrier.newLayout) {
         skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-oldLayout-01181",
-                        "%s: As the Image Barrier for image 0x%" PRIx64
-                        " is being executed within a render pass instance, oldLayout must equal newLayout yet they are %s and %s.",
-                        funcName, HandleToUint64(img_barrier.image), string_VkImageLayout(img_barrier.oldLayout),
-                        string_VkImageLayout(img_barrier.newLayout));
+                        "%s: As the Image Barrier for image %s is being executed within a render pass instance, oldLayout must "
+                        "equal newLayout yet they are %s and %s.",
+                        funcName, device_data->report_data->FormatHandle(img_barrier.image).c_str(),
+                        string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(img_barrier.newLayout));
     } else {
         if (sub_image_found && sub_image_layout != img_barrier.oldLayout) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            rp_handle, "VUID-vkCmdPipelineBarrier-oldLayout-01180",
-                            "%s: Barrier pImageMemoryBarriers[%d].image (0x%" PRIx64
-                            ") is referenced by the VkSubpassDescription for active subpass (%d) of current renderPass (0x%" PRIx64
-                            ") as having layout %s, but image barrier has layout %s.",
-                            funcName, img_index, HandleToUint64(img_bar_image), active_subpass, rp_handle,
-                            string_VkImageLayout(sub_image_layout), string_VkImageLayout(img_barrier.oldLayout));
+                            rp_handle, "VUID-vkCmdPipelineBarrier-oldLayout-02636",
+                            "%s: Barrier pImageMemoryBarriers[%d].image (%s) is referenced by the VkSubpassDescription for active "
+                            "subpass (%d) of current renderPass (%s) as having layout %s, but image barrier has layout %s.",
+                            funcName, img_index, device_data->report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
+                            device_data->report_data->FormatHandle(rp_handle).c_str(), string_VkImageLayout(sub_image_layout),
+                            string_VkImageLayout(img_barrier.oldLayout));
         }
     }
     return skip;
 }
 
 // Validate image barriers within a renderPass
-static bool ValidateRenderPassImageBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
-                                            uint32_t active_subpass, const safe_VkSubpassDescription2KHR &sub_desc,
-                                            uint64_t rp_handle, const safe_VkSubpassDependency2KHR *dependencies,
-                                            const std::vector<uint32_t> &self_dependencies, uint32_t image_mem_barrier_count,
-                                            const VkImageMemoryBarrier *image_barriers) {
+bool CoreChecks::ValidateRenderPassImageBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
+                                                 uint32_t active_subpass, const safe_VkSubpassDescription2KHR &sub_desc,
+                                                 uint64_t rp_handle, const safe_VkSubpassDependency2KHR *dependencies,
+                                                 const std::vector<uint32_t> &self_dependencies, uint32_t image_mem_barrier_count,
+                                                 const VkImageMemoryBarrier *image_barriers) {
     bool skip = false;
     for (uint32_t i = 0; i < image_mem_barrier_count; ++i) {
         const auto &img_barrier = image_barriers[i];
@@ -8260,18 +7785,20 @@
         if (!access_mask_match) {
             std::stringstream self_dep_ss;
             stream_join(self_dep_ss, ", ", self_dependencies);
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
-                            "%s: Barrier pImageMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency "
-                            "srcAccessMask of subpass %d of renderPass 0x%" PRIx64
-                            ". Candidate VkSubpassDependency are pDependencies entries [%s].",
-                            funcName, i, img_src_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
-                            "%s: Barrier pImageMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency "
-                            "dstAccessMask of subpass %d of renderPass 0x%" PRIx64
-                            ". Candidate VkSubpassDependency are pDependencies entries [%s].",
-                            funcName, i, img_dst_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
+                "VUID-vkCmdPipelineBarrier-pDependencies-02285",
+                "%s: Barrier pImageMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency "
+                "srcAccessMask of subpass %d of renderPass %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
+                funcName, i, img_src_access_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                self_dep_ss.str().c_str());
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
+                "VUID-vkCmdPipelineBarrier-pDependencies-02285",
+                "%s: Barrier pImageMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency "
+                "dstAccessMask of subpass %d of renderPass %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
+                funcName, i, img_dst_access_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                self_dep_ss.str().c_str());
         }
         if (VK_QUEUE_FAMILY_IGNORED != img_barrier.srcQueueFamilyIndex ||
             VK_QUEUE_FAMILY_IGNORED != img_barrier.dstQueueFamilyIndex) {
@@ -8299,12 +7826,12 @@
 
 // Validate VUs for Pipeline Barriers that are within a renderPass
 // Pre: cb_state->activeRenderPass must be a pointer to valid renderPass state
-static bool ValidateRenderPassPipelineBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
-                                               VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
-                                               VkDependencyFlags dependency_flags, uint32_t mem_barrier_count,
-                                               const VkMemoryBarrier *mem_barriers, uint32_t buffer_mem_barrier_count,
-                                               const VkBufferMemoryBarrier *buffer_mem_barriers, uint32_t image_mem_barrier_count,
-                                               const VkImageMemoryBarrier *image_barriers) {
+bool CoreChecks::ValidateRenderPassPipelineBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
+                                                    VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
+                                                    VkDependencyFlags dependency_flags, uint32_t mem_barrier_count,
+                                                    const VkMemoryBarrier *mem_barriers, uint32_t buffer_mem_barrier_count,
+                                                    const VkBufferMemoryBarrier *buffer_mem_barriers,
+                                                    uint32_t image_mem_barrier_count, const VkImageMemoryBarrier *image_barriers) {
     bool skip = false;
     const auto rp_state = cb_state->activeRenderPass;
     const auto active_subpass = cb_state->activeSubpass;
@@ -8312,11 +7839,10 @@
     const auto &self_dependencies = rp_state->self_dependencies[active_subpass];
     const auto &dependencies = rp_state->createInfo.pDependencies;
     if (self_dependencies.size() == 0) {
-        skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
-                    "VUID-vkCmdPipelineBarrier-pDependencies-02285",
-                    "%s: Barriers cannot be set during subpass %d of renderPass 0x%" PRIx64 " with no self-dependency specified.",
-                    funcName, active_subpass, rp_handle);
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
+                        rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
+                        "%s: Barriers cannot be set during subpass %d of renderPass %s with no self-dependency specified.",
+                        funcName, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str());
     } else {
         // Grab ref to current subpassDescription up-front for use below
         const auto &sub_desc = rp_state->createInfo.pSubpasses[active_subpass];
@@ -8324,8 +7850,8 @@
         bool stage_mask_match = false;
         for (const auto self_dep_index : self_dependencies) {
             const auto &sub_dep = dependencies[self_dep_index];
-            const auto &sub_src_stage_mask = ExpandPipelineStageFlags(sub_dep.srcStageMask);
-            const auto &sub_dst_stage_mask = ExpandPipelineStageFlags(sub_dep.dstStageMask);
+            const auto &sub_src_stage_mask = ExpandPipelineStageFlags(device_data->device_extensions, sub_dep.srcStageMask);
+            const auto &sub_dst_stage_mask = ExpandPipelineStageFlags(device_data->device_extensions, sub_dep.dstStageMask);
             stage_mask_match = ((sub_src_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
                                 (src_stage_mask == (sub_src_stage_mask & src_stage_mask))) &&
                                ((sub_dst_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
@@ -8338,24 +7864,24 @@
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                             rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
                             "%s: Barrier srcStageMask(0x%X) is not a subset of VkSubpassDependency srcStageMask of any "
-                            "self-dependency of subpass %d of renderPass 0x%" PRIx64
-                            " for which dstStageMask is also a subset. "
+                            "self-dependency of subpass %d of renderPass %s for which dstStageMask is also a subset. "
                             "Candidate VkSubpassDependency are pDependencies entries [%s].",
-                            funcName, src_stage_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+                            funcName, src_stage_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                            self_dep_ss.str().c_str());
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                             rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
                             "%s: Barrier dstStageMask(0x%X) is not a subset of VkSubpassDependency dstStageMask of any "
-                            "self-dependency of subpass %d of renderPass 0x%" PRIx64
-                            " for which srcStageMask is also a subset. "
+                            "self-dependency of subpass %d of renderPass %s for which srcStageMask is also a subset. "
                             "Candidate VkSubpassDependency are pDependencies entries [%s].",
-                            funcName, dst_stage_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+                            funcName, dst_stage_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                            self_dep_ss.str().c_str());
         }
 
         if (0 != buffer_mem_barrier_count) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                             rp_handle, "VUID-vkCmdPipelineBarrier-bufferMemoryBarrierCount-01178",
-                            "%s: bufferMemoryBarrierCount is non-zero (%d) for subpass %d of renderPass 0x%" PRIx64 ".", funcName,
-                            buffer_mem_barrier_count, active_subpass, rp_handle);
+                            "%s: bufferMemoryBarrierCount is non-zero (%d) for subpass %d of renderPass %s.", funcName,
+                            buffer_mem_barrier_count, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str());
         }
         for (uint32_t i = 0; i < mem_barrier_count; ++i) {
             const auto &mb_src_access_mask = mem_barriers[i].srcAccessMask;
@@ -8375,18 +7901,18 @@
                     device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
                     "VUID-vkCmdPipelineBarrier-pDependencies-02285",
                     "%s: Barrier pMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency srcAccessMask "
-                    "for any self-dependency of subpass %d of renderPass 0x%" PRIx64
-                    " for which dstAccessMask is also a subset. "
+                    "for any self-dependency of subpass %d of renderPass %s for which dstAccessMask is also a subset. "
                     "Candidate VkSubpassDependency are pDependencies entries [%s].",
-                    funcName, i, mb_src_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+                    funcName, i, mb_src_access_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                    self_dep_ss.str().c_str());
                 skip |= log_msg(
                     device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
                     "VUID-vkCmdPipelineBarrier-pDependencies-02285",
                     "%s: Barrier pMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency dstAccessMask "
-                    "for any self-dependency of subpass %d of renderPass 0x%" PRIx64
-                    " for which srcAccessMask is also a subset. "
+                    "for any self-dependency of subpass %d of renderPass %s for which srcAccessMask is also a subset. "
                     "Candidate VkSubpassDependency are pDependencies entries [%s].",
-                    funcName, i, mb_dst_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+                    funcName, i, mb_dst_access_mask, active_subpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                    self_dep_ss.str().c_str());
             }
         }
 
@@ -8402,12 +7928,13 @@
         if (!flag_match) {
             std::stringstream self_dep_ss;
             stream_join(self_dep_ss, ", ", self_dependencies);
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
-                            "%s: dependencyFlags param (0x%X) does not equal VkSubpassDependency dependencyFlags value for any "
-                            "self-dependency of subpass %d of renderPass 0x%" PRIx64
-                            ". Candidate VkSubpassDependency are pDependencies entries [%s].",
-                            funcName, dependency_flags, cb_state->activeSubpass, rp_handle, self_dep_ss.str().c_str());
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
+                "VUID-vkCmdPipelineBarrier-pDependencies-02285",
+                "%s: dependencyFlags param (0x%X) does not equal VkSubpassDependency dependencyFlags value for any "
+                "self-dependency of subpass %d of renderPass %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
+                funcName, dependency_flags, cb_state->activeSubpass, device_data->report_data->FormatHandle(rp_handle).c_str(),
+                self_dep_ss.str().c_str());
         }
     }
     return skip;
@@ -8415,7 +7942,7 @@
 
 // Array to mask individual accessMask to corresponding stageMask
 //  accessMask active bit position (0-31) maps to index
-const static VkPipelineStageFlags AccessMaskToPipeStage[24] = {
+const static VkPipelineStageFlags AccessMaskToPipeStage[28] = {
     // VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0
     VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
     // VK_ACCESS_INDEX_READ_BIT = 1
@@ -8426,19 +7953,19 @@
     VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
         VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV |
-        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX,
+        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,
     // VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 4
     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
     // VK_ACCESS_SHADER_READ_BIT = 5
     VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
         VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV |
-        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX,
+        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,
     // VK_ACCESS_SHADER_WRITE_BIT = 6
     VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
         VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV |
-        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX,
+        VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,
     // VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 7
     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
     // VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 8
@@ -8463,25 +7990,33 @@
     VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
     // VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 18
     VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
-    // 19
-    0,
-    // 20
-    0,
-    // VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 21
-    VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX,
-    // VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 22
-    VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX,
+    // VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 19
+    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+    // VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 20
+    VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT,
+    // VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 21
+    VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV | VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV,
+    // VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 22
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV,
     // VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 23
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV,
-
+    // VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 24
+    VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT,
+    // VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 25
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
+    // VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 26
+    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
+    // VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 27
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
 };
 
 // Verify that all bits of access_mask are supported by the src_stage_mask
-static bool ValidateAccessMaskPipelineStage(VkAccessFlags access_mask, VkPipelineStageFlags stage_mask) {
+static bool ValidateAccessMaskPipelineStage(const DeviceExtensions &extensions, VkAccessFlags access_mask,
+                                            VkPipelineStageFlags stage_mask) {
     // Early out if all commands set, or access_mask NULL
     if ((stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) || (0 == access_mask)) return true;
 
-    stage_mask = ExpandPipelineStageFlags(stage_mask);
+    stage_mask = ExpandPipelineStageFlags(extensions, stage_mask);
     int index = 0;
     // for each of the set bits in access_mask, make sure that supporting stage mask bit(s) are set
     while (access_mask) {
@@ -8548,8 +8083,8 @@
           sharing_mode_(sharing_mode),
           object_type_(object_type),
           val_codes_(val_codes),
-          limit_(static_cast<uint32_t>(device_data->phys_dev_properties.queue_family_properties.size())),
-          mem_ext_(device_data->extensions.vk_khr_external_memory) {}
+          limit_(static_cast<uint32_t>(device_data->physical_device_state->queue_family_properties.size())),
+          mem_ext_(device_data->device_extensions.vk_khr_external_memory) {}
 
     // Create a validator state from an image state... reducing the image specific to the generic version.
     ValidatorState(const layer_data *device_data, const char *func_name, const GLOBAL_CB_NODE *cb_state,
@@ -8566,23 +8101,23 @@
     // Log the messages using boilerplate from object state, and Vu specific information from the template arg
     // One and two family versions, in the single family version, Vu holds the name of the passed parameter
     bool LogMsg(VuIndex vu_index, uint32_t family, const char *param_name) const {
-        const std::string val_code = val_codes_[vu_index];
+        const std::string &val_code = val_codes_[vu_index];
         const char *annotation = GetFamilyAnnotation(family);
         return log_msg(report_data_, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, cb_handle64_,
-                       val_code, "%s: Barrier using %s 0x%" PRIx64 " created with sharingMode %s, has %s %u%s. %s", func_name_,
-                       GetTypeString(), barrier_handle64_, GetModeString(), param_name, family, annotation, vu_summary[vu_index]);
+                       val_code, "%s: Barrier using %s %s created with sharingMode %s, has %s %u%s. %s", func_name_,
+                       GetTypeString(), report_data_->FormatHandle(barrier_handle64_).c_str(), GetModeString(), param_name, family,
+                       annotation, vu_summary[vu_index]);
     }
 
     bool LogMsg(VuIndex vu_index, uint32_t src_family, uint32_t dst_family) const {
-        const std::string val_code = val_codes_[vu_index];
+        const std::string &val_code = val_codes_[vu_index];
         const char *src_annotation = GetFamilyAnnotation(src_family);
         const char *dst_annotation = GetFamilyAnnotation(dst_family);
-        return log_msg(report_data_, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, cb_handle64_,
-                       val_code,
-                       "%s: Barrier using %s 0x%" PRIx64
-                       " created with sharingMode %s, has srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
-                       func_name_, GetTypeString(), barrier_handle64_, GetModeString(), src_family, src_annotation, dst_family,
-                       dst_annotation, vu_summary[vu_index]);
+        return log_msg(
+            report_data_, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, cb_handle64_, val_code,
+            "%s: Barrier using %s %s created with sharingMode %s, has srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
+            func_name_, GetTypeString(), report_data_->FormatHandle(barrier_handle64_).c_str(), GetModeString(), src_family,
+            src_annotation, dst_family, dst_annotation, vu_summary[vu_index]);
     }
 
     // This abstract Vu can only be tested at submit time, thus we need a callback from the closure containing the needed
@@ -8595,15 +8130,16 @@
 
         uint32_t queue_family = queue_data_it->second.queueFamilyIndex;
         if ((src_family != queue_family) && (dst_family != queue_family)) {
-            const std::string val_code = val.val_codes_[kSubmitQueueMustMatchSrcOrDst];
+            const std::string &val_code = val.val_codes_[kSubmitQueueMustMatchSrcOrDst];
             const char *src_annotation = val.GetFamilyAnnotation(src_family);
             const char *dst_annotation = val.GetFamilyAnnotation(dst_family);
             return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
                            HandleToUint64(queue), val_code,
-                           "%s: Barrier submitted to queue with family index %u, using %s 0x%" PRIx64
-                           " created with sharingMode %s, has srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
-                           "vkQueueSubmit", queue_family, val.GetTypeString(), val.barrier_handle64_, val.GetModeString(),
-                           src_family, src_annotation, dst_family, dst_annotation, vu_summary[kSubmitQueueMustMatchSrcOrDst]);
+                           "%s: Barrier submitted to queue with family index %u, using %s %s created with sharingMode %s, has "
+                           "srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
+                           "vkQueueSubmit", queue_family, val.GetTypeString(),
+                           device_data->report_data->FormatHandle(val.barrier_handle64_).c_str(), val.GetModeString(), src_family,
+                           src_annotation, dst_family, dst_annotation, vu_summary[kSubmitQueueMustMatchSrcOrDst]);
         }
         return false;
     }
@@ -8738,21 +8274,21 @@
     return barrier_queue_families::Validate(device_data, func_name, cb_state, val, src_queue_family, dst_queue_family);
 }
 
-static bool ValidateBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
-                             VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, uint32_t memBarrierCount,
-                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
-                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
-                             const VkImageMemoryBarrier *pImageMemBarriers) {
+bool CoreChecks::ValidateBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
+                                  VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
+                                  uint32_t memBarrierCount, const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
+                                  const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
+                                  const VkImageMemoryBarrier *pImageMemBarriers) {
     bool skip = false;
     for (uint32_t i = 0; i < memBarrierCount; ++i) {
         const auto &mem_barrier = pMemBarriers[i];
-        if (!ValidateAccessMaskPipelineStage(mem_barrier.srcAccessMask, src_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier.srcAccessMask, src_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01184",
                             "%s: pMemBarriers[%d].srcAccessMask (0x%X) is not supported by srcStageMask (0x%X).", funcName, i,
                             mem_barrier.srcAccessMask, src_stage_mask);
         }
-        if (!ValidateAccessMaskPipelineStage(mem_barrier.dstAccessMask, dst_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier.dstAccessMask, dst_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01185",
                             "%s: pMemBarriers[%d].dstAccessMask (0x%X) is not supported by dstStageMask (0x%X).", funcName, i,
@@ -8761,20 +8297,20 @@
     }
     for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
         auto mem_barrier = &pImageMemBarriers[i];
-        if (!ValidateAccessMaskPipelineStage(mem_barrier->srcAccessMask, src_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier->srcAccessMask, src_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01184",
                             "%s: pImageMemBarriers[%d].srcAccessMask (0x%X) is not supported by srcStageMask (0x%X).", funcName, i,
                             mem_barrier->srcAccessMask, src_stage_mask);
         }
-        if (!ValidateAccessMaskPipelineStage(mem_barrier->dstAccessMask, dst_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier->dstAccessMask, dst_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01185",
                             "%s: pImageMemBarriers[%d].dstAccessMask (0x%X) is not supported by dstStageMask (0x%X).", funcName, i,
                             mem_barrier->dstAccessMask, dst_stage_mask);
         }
 
-        auto image_data = GetImageState(device_data, mem_barrier->image);
+        auto image_data = GetImageState(mem_barrier->image);
         skip |= ValidateBarrierQueueFamilies(device_data, funcName, cb_state, mem_barrier, image_data);
 
         if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
@@ -8803,20 +8339,20 @@
         auto mem_barrier = &pBufferMemBarriers[i];
         if (!mem_barrier) continue;
 
-        if (!ValidateAccessMaskPipelineStage(mem_barrier->srcAccessMask, src_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier->srcAccessMask, src_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01184",
                             "%s: pBufferMemBarriers[%d].srcAccessMask (0x%X) is not supported by srcStageMask (0x%X).", funcName, i,
                             mem_barrier->srcAccessMask, src_stage_mask);
         }
-        if (!ValidateAccessMaskPipelineStage(mem_barrier->dstAccessMask, dst_stage_mask)) {
+        if (!ValidateAccessMaskPipelineStage(device_data->device_extensions, mem_barrier->dstAccessMask, dst_stage_mask)) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdPipelineBarrier-pMemoryBarriers-01185",
                             "%s: pBufferMemBarriers[%d].dstAccessMask (0x%X) is not supported by dstStageMask (0x%X).", funcName, i,
                             mem_barrier->dstAccessMask, dst_stage_mask);
         }
         // Validate buffer barrier queue family indices
-        auto buffer_state = GetBufferState(device_data, mem_barrier->buffer);
+        auto buffer_state = GetBufferState(mem_barrier->buffer);
         skip |= ValidateBarrierQueueFamilies(device_data, funcName, cb_state, mem_barrier, buffer_state);
 
         if (buffer_state) {
@@ -8828,20 +8364,20 @@
 
             auto buffer_size = buffer_state->createInfo.size;
             if (mem_barrier->offset >= buffer_size) {
-                skip |= log_msg(
-                    device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                    HandleToUint64(cb_state->commandBuffer), "VUID-VkBufferMemoryBarrier-offset-01187",
-                    "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
-                    funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
-                    HandleToUint64(buffer_size));
+                skip |=
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), "VUID-VkBufferMemoryBarrier-offset-01187",
+                            "%s: Buffer Barrier %s has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
+                            funcName, device_data->report_data->FormatHandle(mem_barrier->buffer).c_str(),
+                            HandleToUint64(mem_barrier->offset), HandleToUint64(buffer_size));
             } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
                 skip |=
                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(cb_state->commandBuffer), "VUID-VkBufferMemoryBarrier-size-01189",
-                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
+                            "%s: Buffer Barrier %s has offset 0x%" PRIx64 " and size 0x%" PRIx64
                             " whose sum is greater than total size 0x%" PRIx64 ".",
-                            funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
-                            HandleToUint64(mem_barrier->size), HandleToUint64(buffer_size));
+                            funcName, device_data->report_data->FormatHandle(mem_barrier->buffer).c_str(),
+                            HandleToUint64(mem_barrier->offset), HandleToUint64(mem_barrier->size), HandleToUint64(buffer_size));
             }
         }
     }
@@ -8852,8 +8388,8 @@
     return skip;
 }
 
-bool ValidateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
-                            VkPipelineStageFlags sourceStageMask) {
+bool CoreChecks::ValidateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
+                                        VkPipelineStageFlags sourceStageMask) {
     bool skip = false;
     VkPipelineStageFlags stageMask = 0;
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
@@ -8865,11 +8401,12 @@
         if (event_data != queue_data->second.eventToStageMap.end()) {
             stageMask |= event_data->second;
         } else {
-            auto global_event_data = GetEventNode(dev_data, event);
+            auto global_event_data = GetEventNode(event);
             if (!global_event_data) {
                 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
                                 HandleToUint64(event), kVUID_Core_DrawState_InvalidEvent,
-                                "Event 0x%" PRIx64 " cannot be waited on if it has never been set.", HandleToUint64(event));
+                                "Event %s cannot be waited on if it has never been set.",
+                                dev_data->report_data->FormatHandle(event).c_str());
             } else {
                 stageMask |= global_event_data->stageMask;
             }
@@ -8920,9 +8457,9 @@
                                                             VK_PIPELINE_STAGE_TRANSFER_BIT,
                                                             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
 
-bool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
-                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
-                                      std::string error_code) {
+bool CoreChecks::CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer,
+                                                  VkPipelineStageFlags stage_mask, VkQueueFlags queue_flags, const char *function,
+                                                  const char *src_or_dest, const char *error_code) {
     bool skip = false;
     // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
     for (const auto &item : stage_flag_bit_array) {
@@ -8940,7 +8477,7 @@
 
 // Check if all barriers are of a given operation type.
 template <typename Barrier, typename OpCheck>
-static bool AllTransferOp(const COMMAND_POOL_NODE *pool, OpCheck &op_check, uint32_t count, const Barrier *barriers) {
+bool AllTransferOp(const COMMAND_POOL_NODE *pool, OpCheck &op_check, uint32_t count, const Barrier *barriers) {
     if (!pool) return false;
 
     for (uint32_t b = 0; b < count; b++) {
@@ -8949,24 +8486,20 @@
     return true;
 }
 
-enum BarrierOperationsType {
-    kAllAcquire,  // All Barrier operations are "ownership acquire" operations
-    kAllRelease,  // All Barrier operations are "ownership release" operations
-    kGeneral,     // Either no ownership operations or a mix of ownership operation types and/or non-ownership operations
-};
-
 // Look at the barriers to see if we they are all release or all acquire, the result impacts queue properties validation
-BarrierOperationsType ComputeBarrierOperationsType(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t buffer_barrier_count,
-                                                   const VkBufferMemoryBarrier *buffer_barriers, uint32_t image_barrier_count,
-                                                   const VkImageMemoryBarrier *image_barriers) {
-    auto pool = GetCommandPoolNode(device_data, cb_state->createInfo.commandPool);
+BarrierOperationsType CoreChecks::ComputeBarrierOperationsType(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
+                                                               uint32_t buffer_barrier_count,
+                                                               const VkBufferMemoryBarrier *buffer_barriers,
+                                                               uint32_t image_barrier_count,
+                                                               const VkImageMemoryBarrier *image_barriers) {
+    auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
     BarrierOperationsType op_type = kGeneral;
 
     // Look at the barrier details only if they exist
     // Note: AllTransferOp returns true for count == 0
     if ((buffer_barrier_count + image_barrier_count) != 0) {
-        if (AllTransferOp(pool, IsReleaseOp<VkBufferMemoryBarrier>, buffer_barrier_count, buffer_barriers) &&
-            AllTransferOp(pool, IsReleaseOp<VkImageMemoryBarrier>, image_barrier_count, image_barriers)) {
+        if (AllTransferOp(pool, TempIsReleaseOp<VkBufferMemoryBarrier>, buffer_barrier_count, buffer_barriers) &&
+            AllTransferOp(pool, TempIsReleaseOp<VkImageMemoryBarrier>, image_barrier_count, image_barriers)) {
             op_type = kAllRelease;
         } else if (AllTransferOp(pool, IsAcquireOp<VkBufferMemoryBarrier>, buffer_barrier_count, buffer_barriers) &&
                    AllTransferOp(pool, IsAcquireOp<VkImageMemoryBarrier>, image_barrier_count, image_barriers)) {
@@ -8977,14 +8510,14 @@
     return op_type;
 }
 
-bool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE const *cb_state,
-                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
-                                                BarrierOperationsType barrier_op_type, const char *function,
-                                                std::string error_code) {
+bool CoreChecks::ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE const *cb_state,
+                                                            VkPipelineStageFlags source_stage_mask,
+                                                            VkPipelineStageFlags dest_stage_mask,
+                                                            BarrierOperationsType barrier_op_type, const char *function,
+                                                            const char *error_code) {
     bool skip = false;
     uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
+    auto physical_device_state = GetPhysicalDeviceState();
 
     // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
     // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
@@ -9007,37 +8540,45 @@
     return skip;
 }
 
-static bool PreCallValidateCmdEventCount(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineStageFlags sourceStageMask,
-                                         VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount,
-                                         const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount,
-                                         const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount,
-                                         const VkImageMemoryBarrier *pImageMemoryBarriers) {
-    auto barrier_op_type = ComputeBarrierOperationsType(dev_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers,
+bool CoreChecks::PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
+                                              VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
+                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
+                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+
+    auto barrier_op_type = ComputeBarrierOperationsType(device_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers,
                                                         imageMemoryBarrierCount, pImageMemoryBarriers);
-    bool skip = ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, barrier_op_type,
+    bool skip = ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, sourceStageMask, dstStageMask, barrier_op_type,
                                                            "vkCmdWaitEvents", "VUID-vkCmdWaitEvents-srcStageMask-01164");
-    skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", "VUID-vkCmdWaitEvents-srcStageMask-01159",
-                                         "VUID-vkCmdWaitEvents-srcStageMask-01161", "VUID-vkCmdWaitEvents-srcStageMask-02111",
-                                         "VUID-vkCmdWaitEvents-srcStageMask-02112");
-    skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", "VUID-vkCmdWaitEvents-dstStageMask-01160",
+    skip |= ValidateStageMaskGsTsEnables(device_data, sourceStageMask, "vkCmdWaitEvents()",
+                                         "VUID-vkCmdWaitEvents-srcStageMask-01159", "VUID-vkCmdWaitEvents-srcStageMask-01161",
+                                         "VUID-vkCmdWaitEvents-srcStageMask-02111", "VUID-vkCmdWaitEvents-srcStageMask-02112");
+    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdWaitEvents()", "VUID-vkCmdWaitEvents-dstStageMask-01160",
                                          "VUID-vkCmdWaitEvents-dstStageMask-01162", "VUID-vkCmdWaitEvents-dstStageMask-02113",
                                          "VUID-vkCmdWaitEvents-dstStageMask-02114");
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                   "VUID-vkCmdWaitEvents-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
-    skip |= ValidateBarriersToImages(dev_data, cb_state, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
-    skip |= ValidateBarriers(dev_data, "vkCmdWaitEvents()", cb_state, sourceStageMask, dstStageMask, memoryBarrierCount,
+    skip |= ValidateCmd(device_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
+    skip |= ValidateBarriersToImages(device_data, cb_state, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
+    skip |= ValidateBarriers(device_data, "vkCmdWaitEvents()", cb_state, sourceStageMask, dstStageMask, memoryBarrierCount,
                              pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
                              pImageMemoryBarriers);
     return skip;
 }
 
-static void PreCallRecordCmdWaitEvents(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, uint32_t eventCount, const VkEvent *pEvents,
-                                       VkPipelineStageFlags sourceStageMask, uint32_t imageMemoryBarrierCount,
-                                       const VkImageMemoryBarrier *pImageMemoryBarriers) {
+void CoreChecks::PreCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
+                                            VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                            uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
+                                            uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
+                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     auto first_event_index = cb_state->events.size();
     for (uint32_t i = 0; i < eventCount; ++i) {
-        auto event_state = GetEventNode(dev_data, pEvents[i]);
+        auto event_state = GetEventNode(pEvents[i]);
         if (event_state) {
             AddCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(pEvents[i]), kVulkanObjectTypeEvent}, cb_state);
             event_state->cb_bindings.insert(cb_state);
@@ -9047,52 +8588,34 @@
     }
     cb_state->eventUpdates.emplace_back(
         [=](VkQueue q) { return ValidateEventStageMask(q, cb_state, eventCount, first_event_index, sourceStageMask); });
-    TransitionImageLayouts(dev_data, cb_state, imageMemoryBarrierCount, pImageMemoryBarriers);
-}
-
-static void PostCallRecordCmdWaitEvents(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, uint32_t bufferMemoryBarrierCount,
-                                        const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount,
-                                        const VkImageMemoryBarrier *pImageMemoryBarriers) {
-    RecordBarriersQFOTransfers(dev_data, "vkCmdWaitEvents()", cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers,
-                               imageMemoryBarrierCount, pImageMemoryBarriers);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
-                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
-                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
-                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
-                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdEventCount(dev_data, cb_state, sourceStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers,
-                                             bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
-                                             pImageMemoryBarriers);
-        if (!skip) {
-            PreCallRecordCmdWaitEvents(dev_data, cb_state, eventCount, pEvents, sourceStageMask, imageMemoryBarrierCount,
-                                       pImageMemoryBarriers);
-        }
+    TransitionImageLayouts(device_data, cb_state, imageMemoryBarrierCount, pImageMemoryBarriers);
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallValidateCmdWaitEvents(device_data, sourceStageMask);
     }
-    lock.unlock();
-
-    if (!skip) {
-        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
-                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
-                                               imageMemoryBarrierCount, pImageMemoryBarriers);
-    }
-
-    lock.lock();
-    PostCallRecordCmdWaitEvents(dev_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
-                                pImageMemoryBarriers);
 }
 
-static bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkPipelineStageFlags srcStageMask,
-                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
-                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
-                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
-                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
+void CoreChecks::PostCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
+                                             VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                             uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
+                                             uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
+                                             uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    RecordBarriersQFOTransfers(device_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
+                               pImageMemoryBarriers);
+}
+
+bool CoreChecks::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
+                                                   VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
+                                                   uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
+                                                   uint32_t bufferMemoryBarrierCount,
+                                                   const VkBufferMemoryBarrier *pBufferMemoryBarriers,
+                                                   uint32_t imageMemoryBarrierCount,
+                                                   const VkImageMemoryBarrier *pImageMemoryBarriers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+
     bool skip = false;
     auto barrier_op_type = ComputeBarrierOperationsType(device_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers,
                                                         imageMemoryBarrierCount, pImageMemoryBarriers);
@@ -9124,45 +8647,24 @@
     return skip;
 }
 
-static void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                            uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
-                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
-    RecordBarriersQFOTransfers(device_data, "vkCmdPipelineBarrier()", cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers,
-                               imageMemoryBarrierCount, pImageMemoryBarriers);
+void CoreChecks::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
+                                                 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
+                                                 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
+                                                 uint32_t bufferMemoryBarrierCount,
+                                                 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
+                                                 uint32_t imageMemoryBarrierCount,
+                                                 const VkImageMemoryBarrier *pImageMemoryBarriers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+
+    RecordBarriersQFOTransfers(device_data, cb_state, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
+                               pImageMemoryBarriers);
     TransitionImageLayouts(device_data, cb_state, imageMemoryBarrierCount, pImageMemoryBarriers);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
-                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
-                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
-                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
-                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, srcStageMask, dstStageMask, dependencyFlags,
-                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
-                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
-        if (!skip) {
-            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, bufferMemoryBarrierCount, pBufferMemoryBarriers,
-                                            imageMemoryBarrierCount, pImageMemoryBarriers);
-        }
-    } else {
-        assert(0);
-    }
-    lock.unlock();
-    if (!skip) {
-        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
-                                                       memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
-                                                       pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
-    }
-}
-
-static bool SetQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
+bool CoreChecks::SetQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
+    GLOBAL_CB_NODE *pCB = GetCBNode(commandBuffer);
     if (pCB) {
         pCB->queryToStateMap[object] = value;
     }
@@ -9173,121 +8675,96 @@
     return false;
 }
 
-static bool PreCallValidateCmdBeginQuery(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
-    bool skip = ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+bool CoreChecks::PreCallValidateCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                       "VUID-vkCmdBeginQuery-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
+    auto queryType = GetQueryPoolNode(queryPool)->createInfo.queryType;
+
+    if (flags & VK_QUERY_CONTROL_PRECISE_BIT) {
+        if (!device_data->enabled_features.core.occlusionQueryPrecise) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdBeginQuery-queryType-00800",
+                            "VK_QUERY_CONTROL_PRECISE_BIT provided to vkCmdBeginQuery, but precise occlusion queries not enabled "
+                            "on the device.");
+        }
+
+        if (queryType != VK_QUERY_TYPE_OCCLUSION) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdBeginQuery-queryType-00800",
+                "VK_QUERY_CONTROL_PRECISE_BIT provided to vkCmdBeginQuery, but pool query type is not VK_QUERY_TYPE_OCCLUSION");
+        }
+    }
+
+    skip |= ValidateCmd(device_data, cb_state, CMD_BEGINQUERY, "vkCmdBeginQuery()");
     return skip;
 }
 
-static void PostCallRecordCmdBeginQuery(layer_data *dev_data, VkQueryPool queryPool, uint32_t slot, GLOBAL_CB_NODE *pCB) {
+void CoreChecks::PostCallRecordCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     QueryObject query = {queryPool, slot};
-    pCB->activeQueries.insert(query);
-    pCB->startedQueries.insert(query);
-    AddCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
-                            {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, pCB);
+    cb_state->activeQueries.insert(query);
+    cb_state->startedQueries.insert(query);
+    AddCommandBufferBinding(&GetQueryPoolNode(queryPool)->cb_bindings, {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool},
+                            cb_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        PreCallValidateCmdBeginQuery(dev_data, pCB);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
-
-    lock.lock();
-    if (pCB) {
-        PostCallRecordCmdBeginQuery(dev_data, queryPool, slot, pCB);
-    }
-}
-
-static bool PreCallValidateCmdEndQuery(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const QueryObject &query,
-                                       VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
+bool CoreChecks::PreCallValidateCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    QueryObject query = {queryPool, slot};
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
     bool skip = false;
     if (!cb_state->activeQueries.count(query)) {
-        skip |=
-            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                    HandleToUint64(commandBuffer), "VUID-vkCmdEndQuery-None-01923",
-                    "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d.", HandleToUint64(queryPool), slot);
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdEndQuery-None-01923",
+                        "Ending a query before it was started: queryPool %s, index %d.",
+                        device_data->report_data->FormatHandle(queryPool).c_str(), slot);
     }
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                   "VUID-vkCmdEndQuery-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
     return skip;
 }
 
-static void PostCallRecordCmdEndQuery(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const QueryObject &query,
-                                      VkCommandBuffer commandBuffer, VkQueryPool queryPool) {
+void CoreChecks::PostCallRecordCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
+    QueryObject query = {queryPool, slot};
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     cb_state->activeQueries.erase(query);
     cb_state->queryUpdates.emplace_back([=](VkQueue q) { return SetQueryState(q, commandBuffer, query, true); });
-    AddCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
-                            {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
+    AddCommandBufferBinding(&GetQueryPoolNode(queryPool)->cb_bindings, {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool},
+                            cb_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    QueryObject query = {queryPool, slot};
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdEndQuery(dev_data, cb_state, query, commandBuffer, queryPool, slot);
-    }
-    lock.unlock();
+bool CoreChecks::PreCallValidateCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                                  uint32_t queryCount) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
 
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
-
-    lock.lock();
-    if (cb_state) {
-        PostCallRecordCmdEndQuery(dev_data, cb_state, query, commandBuffer, queryPool);
-    }
-}
-
-static bool PreCallValidateCmdResetQueryPool(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    bool skip = InsideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", "VUID-vkCmdResetQueryPool-renderpass");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+    bool skip = InsideRenderPass(device_data, cb_state, "vkCmdResetQueryPool()", "VUID-vkCmdResetQueryPool-renderpass");
+    skip |= ValidateCmd(device_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                   "VUID-vkCmdResetQueryPool-commandBuffer-cmdpool");
     return skip;
 }
 
-static void PostCallRecordCmdResetQueryPool(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                            VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+void CoreChecks::PostCallRecordCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                                 uint32_t queryCount) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+
     for (uint32_t i = 0; i < queryCount; i++) {
         QueryObject query = {queryPool, firstQuery + i};
         cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
         cb_state->queryUpdates.emplace_back([=](VkQueue q) { return SetQueryState(q, commandBuffer, query, false); });
     }
-    AddCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
-                            {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
+    AddCommandBufferBinding(&GetQueryPoolNode(queryPool)->cb_bindings, {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool},
+                            cb_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
-                                             uint32_t queryCount) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    bool skip = PreCallValidateCmdResetQueryPool(dev_data, cb_state);
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
-
-    lock.lock();
-    PostCallRecordCmdResetQueryPool(dev_data, cb_state, commandBuffer, queryPool, firstQuery, queryCount);
-}
-
-static bool IsQueryInvalid(layer_data *dev_data, QUEUE_STATE *queue_data, VkQueryPool queryPool, uint32_t queryIndex) {
+bool CoreChecks::IsQueryInvalid(layer_data *dev_data, QUEUE_STATE *queue_data, VkQueryPool queryPool, uint32_t queryIndex) {
     QueryObject query = {queryPool, queryIndex};
     auto query_data = queue_data->queryToStateMap.find(query);
     if (query_data != queue_data->queryToStateMap.end()) {
@@ -9300,81 +8777,70 @@
     return false;
 }
 
-static bool ValidateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+bool CoreChecks::ValidateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t firstQuery,
+                               uint32_t queryCount) {
     bool skip = false;
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
-    auto queue_data = GetQueueState(dev_data, queue);
+    auto queue_data = GetQueueState(queue);
     if (!queue_data) return false;
     for (uint32_t i = 0; i < queryCount; i++) {
         if (IsQueryInvalid(dev_data, queue_data, queryPool, firstQuery + i)) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidQuery,
-                            "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
-                            HandleToUint64(queryPool), firstQuery + i);
+                            "Requesting a copy from query to buffer with invalid query: queryPool %s, index %d",
+                            dev_data->report_data->FormatHandle(queryPool).c_str(), firstQuery + i);
         }
     }
     return skip;
 }
 
-static bool PreCallValidateCmdCopyQueryPoolResults(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, BUFFER_STATE *dst_buff_state) {
-    bool skip = ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()",
+bool CoreChecks::PreCallValidateCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                                        uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                                        VkDeviceSize stride, VkQueryResultFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_state = GetCBNode(commandBuffer);
+    auto dst_buff_state = GetBufferState(dstBuffer);
+    assert(cb_state);
+    assert(dst_buff_state);
+    bool skip = ValidateMemoryIsBoundToBuffer(device_data, dst_buff_state, "vkCmdCopyQueryPoolResults()",
                                               "VUID-vkCmdCopyQueryPoolResults-dstBuffer-00826");
     // Validate that DST buffer has correct usage flags set
-    skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
+    skip |= ValidateBufferUsageFlags(device_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
                                      "VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825", "vkCmdCopyQueryPoolResults()",
                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdCopyQueryPoolResults()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
-                                  "VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
-    skip |= InsideRenderPass(dev_data, cb_state, "vkCmdCopyQueryPoolResults()", "VUID-vkCmdCopyQueryPoolResults-renderpass");
+    skip |=
+        ValidateCmdQueueFlags(device_data, cb_state, "vkCmdCopyQueryPoolResults()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+                              "VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool");
+    skip |= ValidateCmd(device_data, cb_state, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
+    skip |= InsideRenderPass(device_data, cb_state, "vkCmdCopyQueryPoolResults()", "VUID-vkCmdCopyQueryPoolResults-renderpass");
     return skip;
 }
 
-static void PostCallRecordCmdCopyQueryPoolResults(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, BUFFER_STATE *dst_buff_state,
-                                                  VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
-    AddCommandBufferBindingBuffer(dev_data, cb_state, dst_buff_state);
+void CoreChecks::PostCallRecordCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                                       uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                                       VkDeviceSize stride, VkQueryResultFlags flags) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    auto cb_state = GetCBNode(commandBuffer);
+    auto dst_buff_state = GetBufferState(dstBuffer);
+    AddCommandBufferBindingBuffer(device_data, cb_state, dst_buff_state);
     cb_state->queryUpdates.emplace_back([=](VkQueue q) { return ValidateQuery(q, cb_state, queryPool, firstQuery, queryCount); });
-    AddCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
-                            {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
+    AddCommandBufferBinding(&GetQueryPoolNode(queryPool)->cb_bindings, {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool},
+                            cb_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
-                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
-                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
+bool CoreChecks::PreCallValidateCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
+                                                 VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
+                                                 const void *pValues) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-
-    auto cb_node = GetCBNode(dev_data, commandBuffer);
-    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
-    if (cb_node && dst_buff_state) {
-        skip |= PreCallValidateCmdCopyQueryPoolResults(dev_data, cb_node, dst_buff_state);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride,
-                                                     flags);
-
-    lock.lock();
-    if (cb_node && dst_buff_state) {
-        PostCallRecordCmdCopyQueryPoolResults(dev_data, cb_node, dst_buff_state, queryPool, firstQuery, queryCount);
-    }
-}
-
-static bool PreCallValidateCmdPushConstants(layer_data *dev_data, VkCommandBuffer commandBuffer, VkPipelineLayout layout,
-                                            VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size) {
-    bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
-                                      "VUID-vkCmdPushConstants-commandBuffer-cmdpool");
-        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
-    }
-    skip |= ValidatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+                                  "VUID-vkCmdPushConstants-commandBuffer-cmdpool");
+    skip |= ValidateCmd(device_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
+    skip |= ValidatePushConstantRange(device_data, offset, size, "vkCmdPushConstants()");
     if (0 == stageFlags) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdPushConstants-stageFlags-requiredbitmask",
                         "vkCmdPushConstants() call has no stageFlags set.");
     }
@@ -9382,22 +8848,21 @@
     // Check if pipeline_layout VkPushConstantRange(s) overlapping offset, size have stageFlags set for each stage in the command
     // stageFlags argument, *and* that the command stageFlags argument has bits set for the stageFlags in each overlapping range.
     if (!skip) {
-        const auto &ranges = *GetPipelineLayout(dev_data, layout)->push_constant_ranges;
+        const auto &ranges = *GetPipelineLayout(device_data, layout)->push_constant_ranges;
         VkShaderStageFlags found_stages = 0;
         for (const auto &range : ranges) {
             if ((offset >= range.offset) && (offset + size <= range.offset + range.size)) {
                 VkShaderStageFlags matching_stages = range.stageFlags & stageFlags;
                 if (matching_stages != range.stageFlags) {
                     // "VUID-vkCmdPushConstants-offset-01796" VUID-vkCmdPushConstants-offset-01796
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer),
                                     "VUID-vkCmdPushConstants-offset-01796",
                                     "vkCmdPushConstants(): stageFlags (0x%" PRIx32 ", offset (%" PRIu32 "), and size (%" PRIu32
-                                    "),  "
-                                    "must contain all stages in overlapping VkPushConstantRange stageFlags (0x%" PRIx32
-                                    "), offset (%" PRIu32 "), and size (%" PRIu32 ") in pipeline layout 0x%" PRIx64 ".",
+                                    "),  must contain all stages in overlapping VkPushConstantRange stageFlags (0x%" PRIx32
+                                    "), offset (%" PRIu32 "), and size (%" PRIu32 ") in pipeline layout %s.",
                                     (uint32_t)stageFlags, offset, size, (uint32_t)range.stageFlags, range.offset, range.size,
-                                    HandleToUint64(layout));
+                                    device_data->report_data->FormatHandle(layout).c_str());
                 }
 
                 // Accumulate all stages we've found
@@ -9407,61 +8872,39 @@
         if (found_stages != stageFlags) {
             // "VUID-vkCmdPushConstants-offset-01795" VUID-vkCmdPushConstants-offset-01795
             uint32_t missing_stages = ~found_stages & stageFlags;
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(commandBuffer), "VUID-vkCmdPushConstants-offset-01795",
-                            "vkCmdPushConstants(): stageFlags = 0x%" PRIx32 ", VkPushConstantRange in pipeline layout 0x%" PRIx64
-                            " overlapping offset = %d and size = %d, do not contain stageFlags 0x%" PRIx32 ".",
-                            (uint32_t)stageFlags, HandleToUint64(layout), offset, size, missing_stages);
+            skip |=
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdPushConstants-offset-01795",
+                        "vkCmdPushConstants(): stageFlags = 0x%" PRIx32
+                        ", VkPushConstantRange in pipeline layout %s overlapping offset = %d and size = %d, do not contain "
+                        "stageFlags 0x%" PRIx32 ".",
+                        (uint32_t)stageFlags, device_data->report_data->FormatHandle(layout).c_str(), offset, size, missing_stages);
         }
     }
     return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
-                                            uint32_t offset, uint32_t size, const void *pValues) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    skip |= PreCallValidateCmdPushConstants(dev_data, commandBuffer, layout, stageFlags, offset, size);
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
-}
-
-static bool PreCallValidateCmdWriteTimestamp(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()",
+bool CoreChecks::PreCallValidateCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
+                                                  VkQueryPool queryPool, uint32_t slot) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = ValidateCmdQueueFlags(device_data, cb_state, "vkCmdWriteTimestamp()",
                                       VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
                                       "VUID-vkCmdWriteTimestamp-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
     return skip;
 }
 
-static void PostCallRecordCmdWriteTimestamp(GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer, VkQueryPool queryPool,
-                                            uint32_t slot) {
+void CoreChecks::PostCallRecordCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
+                                                 VkQueryPool queryPool, uint32_t slot) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     QueryObject query = {queryPool, slot};
     cb_state->queryUpdates.emplace_back([=](VkQueue q) { return SetQueryState(q, commandBuffer, query, true); });
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
-                                             VkQueryPool queryPool, uint32_t slot) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdWriteTimestamp(dev_data, cb_state);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
-
-    lock.lock();
-    if (cb_state) PostCallRecordCmdWriteTimestamp(cb_state, commandBuffer, queryPool, slot);
-}
-
-static bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference2KHR *attachments,
-                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag, std::string error_code) {
+bool CoreChecks::MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference2KHR *attachments,
+                            const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag, const char *error_code) {
     bool skip = false;
 
     for (uint32_t attach = 0; attach < count; attach++) {
@@ -9469,9 +8912,9 @@
             // Attachment counts are verified elsewhere, but prevent an invalid access
             if (attachments[attach].attachment < fbci->attachmentCount) {
                 const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
-                auto view_state = GetImageViewState(dev_data, *image_view);
+                auto view_state = GetImageViewState(*image_view);
                 if (view_state) {
-                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
+                    const VkImageCreateInfo *ici = &GetImageState(view_state->create_info.image)->createInfo;
                     if (ici != nullptr) {
                         if ((ici->usage & usage_flag) == 0) {
                             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
@@ -9497,42 +8940,43 @@
 // 6. fb attachments use idenity swizzle
 // 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
 // 8. fb dimensions are within physical device limits
-static bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
+bool CoreChecks::ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
     bool skip = false;
 
-    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
+    auto rp_state = GetRenderPassState(pCreateInfo->renderPass);
     if (rp_state) {
         const VkRenderPassCreateInfo2KHR *rpci = rp_state->createInfo.ptr();
         if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                             HandleToUint64(pCreateInfo->renderPass), "VUID-VkFramebufferCreateInfo-attachmentCount-00876",
                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount "
-                            "of %u of renderPass (0x%" PRIx64 ") being used to create Framebuffer.",
-                            pCreateInfo->attachmentCount, rpci->attachmentCount, HandleToUint64(pCreateInfo->renderPass));
+                            "of %u of renderPass (%s) being used to create Framebuffer.",
+                            pCreateInfo->attachmentCount, rpci->attachmentCount,
+                            dev_data->report_data->FormatHandle(pCreateInfo->renderPass).c_str());
         } else {
             // attachmentCounts match, so make sure corresponding attachment details line up
             const VkImageView *image_views = pCreateInfo->pAttachments;
             for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
-                auto view_state = GetImageViewState(dev_data, image_views[i]);
+                auto view_state = GetImageViewState(image_views[i]);
                 auto &ivci = view_state->create_info;
                 if (ivci.format != rpci->pAttachments[i].format) {
                     skip |=
                         log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                                 HandleToUint64(pCreateInfo->renderPass), "VUID-VkFramebufferCreateInfo-pAttachments-00880",
                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not "
-                                "match the format of %s used by the corresponding attachment for renderPass (0x%" PRIx64 ").",
+                                "match the format of %s used by the corresponding attachment for renderPass (%s).",
                                 i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
-                                HandleToUint64(pCreateInfo->renderPass));
+                                dev_data->report_data->FormatHandle(pCreateInfo->renderPass).c_str());
                 }
-                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
+                const VkImageCreateInfo *ici = &GetImageState(ivci.image)->createInfo;
                 if (ici->samples != rpci->pAttachments[i].samples) {
                     skip |= log_msg(
                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
                         HandleToUint64(pCreateInfo->renderPass), "VUID-VkFramebufferCreateInfo-pAttachments-00881",
                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match the %s "
-                        "samples used by the corresponding attachment for renderPass (0x%" PRIx64 ").",
+                        "samples used by the corresponding attachment for renderPass (%s).",
                         i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
-                        HandleToUint64(pCreateInfo->renderPass));
+                        dev_data->report_data->FormatHandle(pCreateInfo->renderPass).c_str());
                 }
                 // Verify that view only has a single mip level
                 if (ivci.subresourceRange.levelCount != 1) {
@@ -9589,31 +9033,31 @@
             // Verify depth/stencil attachments:
             if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
                 skip |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
-                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-pAttachments-00878");
+                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-pAttachments-02633");
             }
         }
     }
     // Verify FB dimensions are within physical device limits
-    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
+    if (pCreateInfo->width > dev_data->phys_dev_props.limits.maxFramebufferWidth) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkFramebufferCreateInfo-width-00886",
                         "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. Requested "
                         "width: %u, device max: %u\n",
-                        pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth);
+                        pCreateInfo->width, dev_data->phys_dev_props.limits.maxFramebufferWidth);
     }
-    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
+    if (pCreateInfo->height > dev_data->phys_dev_props.limits.maxFramebufferHeight) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkFramebufferCreateInfo-height-00888",
                         "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. Requested "
                         "height: %u, device max: %u\n",
-                        pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight);
+                        pCreateInfo->height, dev_data->phys_dev_props.limits.maxFramebufferHeight);
     }
-    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
+    if (pCreateInfo->layers > dev_data->phys_dev_props.limits.maxFramebufferLayers) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkFramebufferCreateInfo-layers-00890",
                         "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. Requested "
                         "layers: %u, device max: %u\n",
-                        pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers);
+                        pCreateInfo->layers, dev_data->phys_dev_props.limits.maxFramebufferLayers);
     }
     // Verify FB dimensions are greater than zero
     if (pCreateInfo->width <= 0) {
@@ -9634,25 +9078,27 @@
     return skip;
 }
 
-// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
-//  Return true if an error is encountered and callback returns true to skip call down chain
-//   false indicates that call down chain should proceed
-static bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
+bool CoreChecks::PreCallValidateCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     // TODO : Verify that renderPass FB is created with is compatible with FB
     bool skip = false;
-    skip |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
+    skip |= ValidateFramebufferCreateInfo(device_data, pCreateInfo);
     return skip;
 }
 
-// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
-static void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
+void CoreChecks::PostCallRecordCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
+                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer,
+                                                 VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
     // Shadow create info and store in map
     std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
-        new FRAMEBUFFER_STATE(fb, pCreateInfo, GetRenderPassStateSharedPtr(dev_data, pCreateInfo->renderPass)));
+        new FRAMEBUFFER_STATE(*pFramebuffer, pCreateInfo, GetRenderPassStateSharedPtr(pCreateInfo->renderPass)));
 
     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
         VkImageView view = pCreateInfo->pAttachments[i];
-        auto view_state = GetImageViewState(dev_data, view);
+        auto view_state = GetImageViewState(view);
         if (!view_state) {
             continue;
         }
@@ -9663,26 +9109,7 @@
         fb_state->attachments.push_back(fb_info);
 #endif
     }
-    dev_data->frameBufferMap[fb] = std::move(fb_state);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
-                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
-        lock.unlock();
-    }
-    return result;
+    device_data->frameBufferMap[*pFramebuffer] = std::move(fb_state);
 }
 
 static bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
@@ -9702,9 +9129,9 @@
     return false;
 }
 
-static bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
-                                  const std::vector<uint32_t> &dependent_subpasses, const std::vector<DAGNode> &subpass_to_node,
-                                  bool &skip) {
+bool CoreChecks::CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
+                                       const std::vector<uint32_t> &dependent_subpasses,
+                                       const std::vector<DAGNode> &subpass_to_node, bool &skip) {
     bool result = true;
     // Loop through all subpasses that share the same attachment and make sure a dependency exists
     for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
@@ -9729,8 +9156,8 @@
     return result;
 }
 
-static bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo2KHR *pCreateInfo, const int index,
-                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
+bool CoreChecks::CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo2KHR *pCreateInfo, const int index,
+                                const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
     const DAGNode &node = subpass_to_node[index];
     // If this node writes to the attachment return true as next nodes need to preserve the attachment.
     const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[index];
@@ -9777,8 +9204,8 @@
             IsRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
 }
 
-static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
-                                 RENDER_PASS_STATE const *renderPass) {
+bool CoreChecks::ValidateDependencies(layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
+                                      RENDER_PASS_STATE const *renderPass) {
     bool skip = false;
     auto const pFramebufferInfo = framebuffer->createInfo.ptr();
     auto const pCreateInfo = renderPass->createInfo.ptr();
@@ -9796,8 +9223,8 @@
                 overlapping_attachments[j].push_back(i);
                 continue;
             }
-            auto view_state_i = GetImageViewState(dev_data, viewi);
-            auto view_state_j = GetImageViewState(dev_data, viewj);
+            auto view_state_i = GetImageViewState(viewi);
+            auto view_state_j = GetImageViewState(viewj);
             if (!view_state_i || !view_state_j) {
                 continue;
             }
@@ -9808,8 +9235,8 @@
                 overlapping_attachments[j].push_back(i);
                 continue;
             }
-            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
-            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
+            auto image_data_i = GetImageState(view_ci_i.image);
+            auto image_data_j = GetImageState(view_ci_j.image);
             if (!image_data_i || !image_data_j) {
                 continue;
             }
@@ -9821,23 +9248,6 @@
             }
         }
     }
-    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
-        uint32_t attachment = i;
-        for (auto other_attachment : overlapping_attachments[i]) {
-            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
-                                HandleToUint64(framebuffer->framebuffer), "VUID-VkRenderPassCreateInfo-attachment-00833",
-                                "Attachment %d aliases attachment %d but doesn't set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
-                                attachment, other_attachment);
-            }
-            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
-                                HandleToUint64(framebuffer->framebuffer), "VUID-VkRenderPassCreateInfo-attachment-00833",
-                                "Attachment %d aliases attachment %d but doesn't set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
-                                other_attachment, attachment);
-            }
-        }
-    }
     // Find for each attachment the subpasses that use them.
     unordered_set<uint32_t> attachmentIndices;
     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
@@ -9908,8 +9318,32 @@
     return skip;
 }
 
-static bool CreatePassDAG(const layer_data *dev_data, RenderPassCreateVersion rp_version,
-                          const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
+static void RecordRenderPassDAG(const layer_data *dev_data, RenderPassCreateVersion rp_version,
+                                const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
+    auto &subpass_to_node = render_pass->subpassToNode;
+    subpass_to_node.resize(pCreateInfo->subpassCount);
+    auto &self_dependencies = render_pass->self_dependencies;
+    self_dependencies.resize(pCreateInfo->subpassCount);
+
+    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
+        subpass_to_node[i].pass = i;
+        self_dependencies[i].clear();
+    }
+    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
+        const VkSubpassDependency2KHR &dependency = pCreateInfo->pDependencies[i];
+        if ((dependency.srcSubpass != VK_SUBPASS_EXTERNAL) && (dependency.dstSubpass != VK_SUBPASS_EXTERNAL)) {
+            if (dependency.srcSubpass == dependency.dstSubpass) {
+                self_dependencies[dependency.srcSubpass].push_back(i);
+            } else {
+                subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
+                subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
+            }
+        }
+    }
+}
+
+static bool ValidateRenderPassDAG(const layer_data *dev_data, RenderPassCreateVersion rp_version,
+                                  const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
     // Shorthand...
     auto &subpass_to_node = render_pass->subpassToNode;
     subpass_to_node.resize(pCreateInfo->subpassCount);
@@ -9927,7 +9361,8 @@
     for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
         const VkSubpassDependency2KHR &dependency = pCreateInfo->pDependencies[i];
         VkPipelineStageFlags exclude_graphics_pipeline_stages =
-            ~(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | ExpandPipelineStageFlags(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT));
+            ~(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT |
+              ExpandPipelineStageFlags(dev_data->device_extensions, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT));
         VkPipelineStageFlagBits latest_src_stage = GetLogicallyLatestGraphicsPipelineStage(dependency.srcStageMask);
         VkPipelineStageFlagBits earliest_dst_stage = GetLogicallyEarliestGraphicsPipelineStage(dependency.dstStageMask);
 
@@ -9977,10 +9412,11 @@
         }
         // The first subpass here serves as a good proxy for "is multiview enabled" - since all view masks need to be non-zero if
         // any are, which enables multiview.
-        else if (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT && pCreateInfo->pSubpasses[0].viewMask == 0) {
-            vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059" : "VUID-VkSubpassDependency-dependencyFlags-00871";
+        else if (use_rp2 && (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) &&
+                 (pCreateInfo->pSubpasses[0].viewMask == 0)) {
             skip |= log_msg(
-                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059",
                 "Dependency %u specifies the VK_DEPENDENCY_VIEW_LOCAL_BIT, but multiview is not enabled for this render pass.", i);
         } else if (use_rp2 && !(dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) && dependency.viewOffset != 0) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -9993,7 +9429,11 @@
                 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 vuid, "The src and dst subpasses in dependency %u are both external.", i);
             } else if (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) {
-                vuid = "VUID-VkSubpassDependency-dependencyFlags-00870";
+                if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL) {
+                    vuid = "VUID-VkSubpassDependency-dependencyFlags-02520";
+                } else {  // dependency.dstSubpass == VK_SUBPASS_EXTERNAL
+                    vuid = "VUID-VkSubpassDependency-dependencyFlags-02521";
+                }
                 if (use_rp2) {
                     // Create render pass 2 distinguishes between source and destination external dependencies.
                     if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL) {
@@ -10047,30 +9487,8 @@
     return skip;
 }
 
-static void PostCallRecordCreateShaderModule(layer_data *dev_data, bool spirv_valid, const VkShaderModuleCreateInfo *pCreateInfo,
-                                             VkShaderModule *pShaderModule) {
-    unique_ptr<shader_module> new_shader_module(spirv_valid ? new shader_module(pCreateInfo, *pShaderModule) : new shader_module());
-    dev_data->shaderModuleMap[*pShaderModule] = std::move(new_shader_module);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
-                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool spirv_valid;
-
-    if (PreCallValidateCreateShaderModule(dev_data, pCreateInfo, &spirv_valid)) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
-
-    if (res == VK_SUCCESS) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateShaderModule(dev_data, spirv_valid, pCreateInfo, pShaderModule);
-    }
-    return res;
-}
-
-static bool ValidateAttachmentIndex(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t attachment,
-                                    uint32_t attachment_count, const char *type) {
+bool CoreChecks::ValidateAttachmentIndex(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t attachment,
+                                         uint32_t attachment_count, const char *type) {
     bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()";
@@ -10085,8 +9503,6 @@
     return skip;
 }
 
-static bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
-
 enum AttachmentType {
     ATTACHMENT_COLOR = 1,
     ATTACHMENT_DEPTH = 2,
@@ -10112,9 +9528,9 @@
     }
 }
 
-static bool AddAttachmentUse(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t subpass,
-                             std::vector<uint8_t> &attachment_uses, std::vector<VkImageLayout> &attachment_layouts,
-                             uint32_t attachment, uint8_t new_use, VkImageLayout new_layout) {
+bool CoreChecks::AddAttachmentUse(const layer_data *dev_data, RenderPassCreateVersion rp_version, uint32_t subpass,
+                                  std::vector<uint8_t> &attachment_uses, std::vector<VkImageLayout> &attachment_layouts,
+                                  uint32_t attachment, uint8_t new_use, VkImageLayout new_layout) {
     if (attachment >= attachment_uses.size()) return false; /* out of range, but already reported */
 
     bool skip = false;
@@ -10124,9 +9540,12 @@
     const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()";
 
     if (uses & new_use) {
-        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                kVUID_Core_DrawState_InvalidRenderpass, "%s: subpass %u already uses attachment %u as a %s attachment.",
-                function_name, subpass, attachment, StringAttachmentType(new_use));
+        if (attachment_layouts[attachment] != new_layout) {
+            vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-layout-02528" : "VUID-VkSubpassDescription-layout-02519";
+            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                    "%s: subpass %u already uses attachment %u with a different image layout (%s vs %s).", function_name, subpass,
+                    attachment, string_VkImageLayout(attachment_layouts[attachment]), string_VkImageLayout(new_layout));
+        }
     } else if (uses & ~ATTACHMENT_INPUT || (uses && (new_use == ATTACHMENT_RESOLVE || new_use == ATTACHMENT_PRESERVE))) {
         /* Note: input attachments are assumed to be done first. */
         vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074"
@@ -10134,13 +9553,6 @@
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
                         "%s: subpass %u uses attachment %u as both %s and %s attachment.", function_name, subpass, attachment,
                         StringAttachmentType(uses), StringAttachmentType(new_use));
-    } else if (uses && attachment_layouts[attachment] != new_layout) {
-        vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-layout-03075" : "VUID-VkSubpassDescription-layout-00855";
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                        "%s: subpass %u uses attachment %u with conflicting layouts: input uses %s, but %s "
-                        "attachment uses %s.",
-                        function_name, subpass, attachment, string_VkImageLayout(attachment_layouts[attachment]),
-                        StringAttachmentType(new_use), string_VkImageLayout(new_layout));
     } else {
         attachment_layouts[attachment] = new_layout;
         uses |= new_use;
@@ -10149,8 +9561,8 @@
     return skip;
 }
 
-static bool ValidateRenderpassAttachmentUsage(const layer_data *dev_data, RenderPassCreateVersion rp_version,
-                                              const VkRenderPassCreateInfo2KHR *pCreateInfo) {
+bool CoreChecks::ValidateRenderpassAttachmentUsage(const layer_data *dev_data, RenderPassCreateVersion rp_version,
+                                                   const VkRenderPassCreateInfo2KHR *pCreateInfo) {
     bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *vuid;
@@ -10320,7 +9732,7 @@
                     const auto depth_stencil_sample_count =
                         pCreateInfo->pAttachments[subpass.pDepthStencilAttachment->attachment].samples;
 
-                    if (dev_data->extensions.vk_amd_mixed_attachment_samples) {
+                    if (dev_data->device_extensions.vk_amd_mixed_attachment_samples) {
                         if (pCreateInfo->pAttachments[attachment_ref.attachment].samples > depth_stencil_sample_count) {
                             vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pColorAttachments-03070"
                                            : "VUID-VkSubpassDescription-pColorAttachments-01506";
@@ -10336,8 +9748,8 @@
                         }
                     }
 
-                    if (!dev_data->extensions.vk_amd_mixed_attachment_samples &&
-                        !dev_data->extensions.vk_nv_framebuffer_mixed_samples &&
+                    if (!dev_data->device_extensions.vk_amd_mixed_attachment_samples &&
+                        !dev_data->device_extensions.vk_nv_framebuffer_mixed_samples &&
                         current_sample_count != depth_stencil_sample_count) {
                         vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071"
                                        : "VUID-VkSubpassDescription-pDepthStencilAttachment-01418";
@@ -10388,8 +9800,8 @@
     if (!render_pass->attachment_first_read.count(index)) render_pass->attachment_first_read[index] = is_read;
 }
 
-static bool ValidateCreateRenderPass(const layer_data *dev_data, VkDevice device, RenderPassCreateVersion rp_version,
-                                     const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
+bool CoreChecks::ValidateCreateRenderPass(layer_data *dev_data, VkDevice device, RenderPassCreateVersion rp_version,
+                                          const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
     bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *vuid;
@@ -10400,7 +9812,7 @@
     skip |= ValidateRenderpassAttachmentUsage(dev_data, rp_version, pCreateInfo);
 
     render_pass->renderPass = VK_NULL_HANDLE;
-    skip |= CreatePassDAG(dev_data, rp_version, pCreateInfo, render_pass);
+    skip |= ValidateRenderPassDAG(dev_data, rp_version, pCreateInfo, render_pass);
 
     // Validate multiview correlation and view masks
     bool viewMaskZero = false;
@@ -10454,12 +9866,12 @@
         if (rp_version == RENDER_PASS_VERSION_2) {
             skip |= ValidateStageMaskGsTsEnables(
                 dev_data, dependency.srcStageMask, function_name, "VUID-VkSubpassDependency2KHR-srcStageMask-03080",
-                "VUID-VkSubpassDependency2KHR-srcStageMask-03082", "VUID-VkSubpassDependency-srcStageMask-02103",
-                "VUID-VkSubpassDependency-srcStageMask-02104");
+                "VUID-VkSubpassDependency2KHR-srcStageMask-03082", "VUID-VkSubpassDependency2KHR-srcStageMask-02103",
+                "VUID-VkSubpassDependency2KHR-srcStageMask-02104");
             skip |= ValidateStageMaskGsTsEnables(
                 dev_data, dependency.dstStageMask, function_name, "VUID-VkSubpassDependency2KHR-dstStageMask-03081",
-                "VUID-VkSubpassDependency2KHR-dstStageMask-03083", "VUID-VkSubpassDependency-srcStageMask-02105",
-                "VUID-VkSubpassDependency-srcStageMask-02106");
+                "VUID-VkSubpassDependency2KHR-dstStageMask-03083", "VUID-VkSubpassDependency2KHR-dstStageMask-02105",
+                "VUID-VkSubpassDependency2KHR-dstStageMask-02106");
         } else {
             skip |= ValidateStageMaskGsTsEnables(
                 dev_data, dependency.srcStageMask, function_name, "VUID-VkSubpassDependency-srcStageMask-00860",
@@ -10471,14 +9883,14 @@
                 "VUID-VkSubpassDependency-dstStageMask-02102");
         }
 
-        if (!ValidateAccessMaskPipelineStage(dependency.srcAccessMask, dependency.srcStageMask)) {
+        if (!ValidateAccessMaskPipelineStage(dev_data->device_extensions, dependency.srcAccessMask, dependency.srcStageMask)) {
             vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-srcAccessMask-03088" : "VUID-VkSubpassDependency-srcAccessMask-00868";
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
                             "%s: pDependencies[%u].srcAccessMask (0x%" PRIx32 ") is not supported by srcStageMask (0x%" PRIx32 ").",
                             function_name, i, dependency.srcAccessMask, dependency.srcStageMask);
         }
 
-        if (!ValidateAccessMaskPipelineStage(dependency.dstAccessMask, dependency.dstStageMask)) {
+        if (!ValidateAccessMaskPipelineStage(dev_data->device_extensions, dependency.dstAccessMask, dependency.dstStageMask)) {
             vuid = use_rp2 ? "VUID-VkSubpassDependency2KHR-dstAccessMask-03089" : "VUID-VkSubpassDependency-dstAccessMask-00869";
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
                             "%s: pDependencies[%u].dstAccessMask (0x%" PRIx32 ") is not supported by dstStageMask (0x%" PRIx32 ").",
@@ -10491,19 +9903,21 @@
     return skip;
 }
 
-static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                            RENDER_PASS_STATE *render_pass) {
+bool CoreChecks::PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     bool skip = false;
     // Handle extension structs from KHR_multiview and KHR_maintenance2 that can only be validated for RP1 (indices out of bounds)
     const VkRenderPassMultiviewCreateInfo *pMultiviewInfo = lvl_find_in_chain<VkRenderPassMultiviewCreateInfo>(pCreateInfo->pNext);
     if (pMultiviewInfo) {
         if (pMultiviewInfo->subpassCount && pMultiviewInfo->subpassCount != pCreateInfo->subpassCount) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-VkRenderPassCreateInfo-pNext-01928",
                             "Subpass count is %u but multiview info has a subpass count of %u.", pCreateInfo->subpassCount,
                             pMultiviewInfo->subpassCount);
         } else if (pMultiviewInfo->dependencyCount && pMultiviewInfo->dependencyCount != pCreateInfo->dependencyCount) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-VkRenderPassCreateInfo-pNext-01929",
                             "Dependency count is %u but multiview info has a dependency count of %u.", pCreateInfo->dependencyCount,
                             pMultiviewInfo->dependencyCount);
@@ -10516,13 +9930,13 @@
             uint32_t subpass = pInputAttachmentAspectInfo->pAspectReferences[i].subpass;
             uint32_t attachment = pInputAttachmentAspectInfo->pAspectReferences[i].inputAttachmentIndex;
             if (subpass >= pCreateInfo->subpassCount) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 "VUID-VkRenderPassCreateInfo-pNext-01926",
                                 "Subpass index %u specified by input attachment aspect info %u is greater than the subpass "
                                 "count of %u for this render pass.",
                                 subpass, i, pCreateInfo->subpassCount);
             } else if (pCreateInfo->pSubpasses && attachment >= pCreateInfo->pSubpasses[subpass].inputAttachmentCount) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 "VUID-VkRenderPassCreateInfo-pNext-01927",
                                 "Input attachment index %u specified by input attachment aspect info %u is greater than the "
                                 "input attachment count of %u for this subpass.",
@@ -10532,21 +9946,23 @@
     }
 
     if (!skip) {
-        skip |= ValidateCreateRenderPass(dev_data, device, RENDER_PASS_VERSION_1, render_pass->createInfo.ptr(), render_pass);
+        auto render_pass = std::unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
+        skip |=
+            ValidateCreateRenderPass(device_data, device, RENDER_PASS_VERSION_1, render_pass->createInfo.ptr(), render_pass.get());
     }
+
     return skip;
 }
 
-// Style note:
-// Use of rvalue reference exceeds reccommended usage of rvalue refs in google style guide, but intentionally forces caller to move
-// or copy.  This is clearer than passing a pointer to shared_ptr and avoids the atomic increment/decrement of shared_ptr copy
-// construction or assignment.
-static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderPass render_pass_handle,
-                                           std::shared_ptr<RENDER_PASS_STATE> &&render_pass) {
-    render_pass->renderPass = render_pass_handle;
-    auto pCreateInfo = render_pass->createInfo.ptr();
-    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
-        const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i];
+void RecordCreateRenderPassState(layer_data *device_data, RenderPassCreateVersion rp_version,
+                                 std::shared_ptr<RENDER_PASS_STATE> &render_pass, VkRenderPass *pRenderPass) {
+    render_pass->renderPass = *pRenderPass;
+    auto create_info = render_pass->createInfo.ptr();
+
+    RecordRenderPassDAG(device_data, RENDER_PASS_VERSION_1, create_info, render_pass.get());
+
+    for (uint32_t i = 0; i < create_info->subpassCount; ++i) {
+        const VkSubpassDescription2KHR &subpass = create_info->pSubpasses[i];
         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
             MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
 
@@ -10564,68 +9980,177 @@
     }
 
     // Even though render_pass is an rvalue-ref parameter, still must move s.t. move assignment is invoked.
-    dev_data->renderPassMap[render_pass_handle] = std::move(render_pass);
+    device_data->renderPassMap[*pRenderPass] = std::move(render_pass);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+// Style note:
+// Use of rvalue reference exceeds reccommended usage of rvalue refs in google style guide, but intentionally forces caller to move
+// or copy.  This is clearer than passing a pointer to shared_ptr and avoids the atomic increment/decrement of shared_ptr copy
+// construction or assignment.
+void CoreChecks::PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
+                                                VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    auto render_pass_state = std::make_shared<RENDER_PASS_STATE>(pCreateInfo);
+    RecordCreateRenderPassState(device_data, RENDER_PASS_VERSION_1, render_pass_state, pRenderPass);
+}
+
+void CoreChecks::PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
+                                                    VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    auto render_pass_state = std::make_shared<RENDER_PASS_STATE>(pCreateInfo);
+    RecordCreateRenderPassState(device_data, RENDER_PASS_VERSION_2, render_pass_state, pRenderPass);
+}
+
+static bool ValidateDepthStencilResolve(const debug_report_data *report_data,
+                                        const VkPhysicalDeviceDepthStencilResolvePropertiesKHR &depth_stencil_resolve_props,
+                                        const VkRenderPassCreateInfo2KHR *pCreateInfo) {
     bool skip = false;
 
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // If we fail, this will act like a unique_ptr and auto-cleanup, as we aren't saving it anywhere
-    auto render_pass = std::make_shared<RENDER_PASS_STATE>(pCreateInfo);
+    // If the pNext list of VkSubpassDescription2KHR includes a VkSubpassDescriptionDepthStencilResolveKHR structure,
+    // then that structure describes depth/stencil resolve operations for the subpass.
+    for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
+        VkSubpassDescription2KHR subpass = pCreateInfo->pSubpasses[i];
+        const auto *resolve = lvl_find_in_chain<VkSubpassDescriptionDepthStencilResolveKHR>(subpass.pNext);
 
-    unique_lock_t lock(global_lock);
+        if (resolve == nullptr) {
+            continue;
+        }
 
-    skip = PreCallValidateCreateRenderPass(dev_data, device, pCreateInfo, render_pass.get());
-    lock.unlock();
+        if (resolve->pDepthStencilResolveAttachment != nullptr &&
+            resolve->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED) {
+            if (subpass.pDepthStencilAttachment->attachment == VK_ATTACHMENT_UNUSED) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03177",
+                                "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                                "structure with resolve attachment %u, but pDepthStencilAttachment=VK_ATTACHMENT_UNUSED.",
+                                i, resolve->pDepthStencilResolveAttachment->attachment);
+            }
+            if (resolve->depthResolveMode == VK_RESOLVE_MODE_NONE_KHR && resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE_KHR) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03178",
+                                "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                                "structure with resolve attachment %u, but both depth and stencil resolve modes are "
+                                "VK_RESOLVE_MODE_NONE_KHR.",
+                                i, resolve->pDepthStencilResolveAttachment->attachment);
+            }
+        }
 
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
+        if (resolve->pDepthStencilResolveAttachment != nullptr &&
+            pCreateInfo->pAttachments[subpass.pDepthStencilAttachment->attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
+            skip |= log_msg(
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03179",
+                "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                "structure with resolve attachment %u. However pDepthStencilAttachment has sample count=VK_SAMPLE_COUNT_1_BIT.",
+                i, resolve->pDepthStencilResolveAttachment->attachment);
+        }
+
+        if (pCreateInfo->pAttachments[resolve->pDepthStencilResolveAttachment->attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03180",
+                            "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                            "structure with resolve attachment %u which has sample count=VK_SAMPLE_COUNT_1_BIT.",
+                            i, resolve->pDepthStencilResolveAttachment->attachment);
+        }
+
+        VkFormat pDepthStencilAttachmentFormat = pCreateInfo->pAttachments[subpass.pDepthStencilAttachment->attachment].format;
+        VkFormat pDepthStencilResolveAttachmentFormat =
+            pCreateInfo->pAttachments[resolve->pDepthStencilResolveAttachment->attachment].format;
+
+        if ((FormatDepthSize(pDepthStencilAttachmentFormat) != FormatDepthSize(pDepthStencilResolveAttachmentFormat)) ||
+            (FormatDepthNumericalType(pDepthStencilAttachmentFormat) !=
+             FormatDepthNumericalType(pDepthStencilResolveAttachmentFormat))) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03181",
+                        "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                        "structure with resolve attachment %u which has a depth component (size %u). The depth component "
+                        "of pDepthStencilAttachment must have the same number of bits (currently %u) and the same numerical type.",
+                        i, resolve->pDepthStencilResolveAttachment->attachment,
+                        FormatDepthSize(pDepthStencilResolveAttachmentFormat), FormatDepthSize(pDepthStencilAttachmentFormat));
+        }
+
+        if ((FormatStencilSize(pDepthStencilAttachmentFormat) != FormatStencilSize(pDepthStencilResolveAttachmentFormat)) ||
+            (FormatStencilNumericalType(pDepthStencilAttachmentFormat) !=
+             FormatStencilNumericalType(pDepthStencilResolveAttachmentFormat))) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03182",
+                        "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                        "structure with resolve attachment %u which has a stencil component (size %u). The stencil component "
+                        "of pDepthStencilAttachment must have the same number of bits (currently %u) and the same numerical type.",
+                        i, resolve->pDepthStencilResolveAttachment->attachment,
+                        FormatStencilSize(pDepthStencilResolveAttachmentFormat), FormatStencilSize(pDepthStencilAttachmentFormat));
+        }
+
+        if (!(resolve->depthResolveMode == VK_RESOLVE_MODE_NONE_KHR ||
+              resolve->depthResolveMode & depth_stencil_resolve_props.supportedDepthResolveModes)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkSubpassDescriptionDepthStencilResolveKHR-depthResolveMode-03183",
+                            "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                            "structure with invalid depthResolveMode=%u.",
+                            i, resolve->depthResolveMode);
+        }
+
+        if (!(resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE_KHR ||
+              resolve->stencilResolveMode & depth_stencil_resolve_props.supportedStencilResolveModes)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkSubpassDescriptionDepthStencilResolveKHR-stencilResolveMode-03184",
+                            "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                            "structure with invalid stencilResolveMode=%u.",
+                            i, resolve->stencilResolveMode);
+        }
+
+        if (FormatIsDepthAndStencil(pDepthStencilResolveAttachmentFormat) &&
+            depth_stencil_resolve_props.independentResolve == VK_FALSE &&
+            depth_stencil_resolve_props.independentResolveNone == VK_FALSE &&
+            !(resolve->depthResolveMode == resolve->stencilResolveMode)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03185",
+                            "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                            "structure. The values of depthResolveMode (%u) and stencilResolveMode (%u) must be identical.",
+                            i, resolve->depthResolveMode, resolve->stencilResolveMode);
+        }
+
+        if (FormatIsDepthAndStencil(pDepthStencilResolveAttachmentFormat) &&
+            depth_stencil_resolve_props.independentResolve == VK_FALSE &&
+            depth_stencil_resolve_props.independentResolveNone == VK_TRUE &&
+            !(resolve->depthResolveMode == resolve->stencilResolveMode || resolve->depthResolveMode == VK_RESOLVE_MODE_NONE_KHR ||
+              resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE_KHR)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03186",
+                            "vkCreateRenderPass2KHR(): Subpass %u includes a VkSubpassDescriptionDepthStencilResolveKHR "
+                            "structure. The values of depthResolveMode (%u) and stencilResolveMode (%u) must be identical, or "
+                            "one of them must be %u.",
+                            i, resolve->depthResolveMode, resolve->stencilResolveMode, VK_RESOLVE_MODE_NONE_KHR);
+        }
     }
 
-    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateRenderPass(dev_data, *pRenderPass, std::move(render_pass));
-    }
-    return result;
+    return skip;
 }
 
-static bool PreCallValidateCreateRenderPass2KHR(const layer_data *dev_data, VkDevice device,
-                                                const VkRenderPassCreateInfo2KHR *pCreateInfo, RENDER_PASS_STATE *render_pass) {
-    return ValidateCreateRenderPass(dev_data, device, RENDER_PASS_VERSION_2, pCreateInfo, render_pass);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+bool CoreChecks::PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
 
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    // If we fail, this will act like a unique_ptr and auto-cleanup, as we aren't saving it anywhere
+    if (GetDeviceExtensions()->vk_khr_depth_stencil_resolve) {
+        skip |= ValidateDepthStencilResolve(device_data->report_data, device_data->phys_dev_ext_props.depth_stencil_resolve_props,
+                                            pCreateInfo);
+    }
+
     auto render_pass = std::make_shared<RENDER_PASS_STATE>(pCreateInfo);
+    skip |= ValidateCreateRenderPass(device_data, device, RENDER_PASS_VERSION_2, render_pass->createInfo.ptr(), render_pass.get());
 
-    unique_lock_t lock(global_lock);
-
-    skip = PreCallValidateCreateRenderPass2KHR(dev_data, device, pCreateInfo, render_pass.get());
-    lock.unlock();
-
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-
-    VkResult result = dev_data->dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        PostCallRecordCreateRenderPass(dev_data, *pRenderPass, std::move(render_pass));
-    }
-    return result;
+    return skip;
 }
 
-static bool ValidatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
-                                         std::string error_code) {
+bool CoreChecks::ValidatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
+                                              const char *error_code) {
     bool skip = false;
     if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -10635,10 +10160,9 @@
     return skip;
 }
 
-static bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
+bool CoreChecks::VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
     bool skip = false;
-    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
-        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
+    const safe_VkFramebufferCreateInfo *pFramebufferInfo = &GetFramebufferState(pRenderPassBegin->framebuffer)->createInfo;
     if (pRenderPassBegin->renderArea.offset.x < 0 ||
         (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
         pRenderPassBegin->renderArea.offset.y < 0 ||
@@ -10668,12 +10192,13 @@
     return ((check_color_depth_load_op && (color_depth_op == op)) || (check_stencil_load_op && (stencil_op == op)));
 }
 
-static bool PreCallValidateCmdBeginRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version,
-                                              const VkRenderPassBeginInfo *pRenderPassBegin) {
-    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
-    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
-
+bool CoreChecks::ValidateCmdBeginRenderPass(layer_data *device_data, VkCommandBuffer commandBuffer,
+                                            RenderPassCreateVersion rp_version, const VkRenderPassBeginInfo *pRenderPassBegin) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     assert(cb_state);
+    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(pRenderPassBegin->renderPass) : nullptr;
+    auto framebuffer = pRenderPassBegin ? GetFramebufferState(pRenderPassBegin->framebuffer) : nullptr;
+
     bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *vuid;
@@ -10689,24 +10214,26 @@
             for (uint32_t i = 0; i < pSampleLocationsBeginInfo->attachmentInitialSampleLocationsCount; ++i) {
                 if (pSampleLocationsBeginInfo->pAttachmentInitialSampleLocations[i].attachmentIndex >=
                     render_pass_state->createInfo.attachmentCount) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
-                                    0, "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531",
-                                    "Attachment index %u specified by attachment sample locations %u is greater than the "
-                                    "attachment count of %u for the render pass being begun.",
-                                    pSampleLocationsBeginInfo->pAttachmentInitialSampleLocations[i].attachmentIndex, i,
-                                    render_pass_state->createInfo.attachmentCount);
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531",
+                                "Attachment index %u specified by attachment sample locations %u is greater than the "
+                                "attachment count of %u for the render pass being begun.",
+                                pSampleLocationsBeginInfo->pAttachmentInitialSampleLocations[i].attachmentIndex, i,
+                                render_pass_state->createInfo.attachmentCount);
                 }
             }
 
             for (uint32_t i = 0; i < pSampleLocationsBeginInfo->postSubpassSampleLocationsCount; ++i) {
                 if (pSampleLocationsBeginInfo->pPostSubpassSampleLocations[i].subpassIndex >=
                     render_pass_state->createInfo.subpassCount) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
-                                    0, "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532",
-                                    "Subpass index %u specified by subpass sample locations %u is greater than the subpass count "
-                                    "of %u for the render pass being begun.",
-                                    pSampleLocationsBeginInfo->pPostSubpassSampleLocations[i].subpassIndex, i,
-                                    render_pass_state->createInfo.subpassCount);
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532",
+                                "Subpass index %u specified by subpass sample locations %u is greater than the subpass count "
+                                "of %u for the render pass being begun.",
+                                pSampleLocationsBeginInfo->pPostSubpassSampleLocations[i].subpassIndex, i,
+                                render_pass_state->createInfo.subpassCount);
                 }
             }
         }
@@ -10720,48 +10247,62 @@
         }
 
         if (clear_op_size > pRenderPassBegin->clearValueCount) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
-                            HandleToUint64(render_pass_state->renderPass), "VUID-VkRenderPassBeginInfo-clearValueCount-00902",
-                            "In %s the VkRenderPassBeginInfo struct has a clearValueCount of %u but there "
-                            "must be at least %u entries in pClearValues array to account for the highest index attachment in "
-                            "renderPass 0x%" PRIx64
-                            " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array is indexed by "
-                            "attachment number so even if some pClearValues entries between 0 and %u correspond to attachments "
-                            "that aren't cleared they will be ignored.",
-                            function_name, pRenderPassBegin->clearValueCount, clear_op_size,
-                            HandleToUint64(render_pass_state->renderPass), clear_op_size, clear_op_size - 1);
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
+                HandleToUint64(render_pass_state->renderPass), "VUID-VkRenderPassBeginInfo-clearValueCount-00902",
+                "In %s the VkRenderPassBeginInfo struct has a clearValueCount of %u but there "
+                "must be at least %u entries in pClearValues array to account for the highest index attachment in "
+                "renderPass %s that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array is indexed by "
+                "attachment number so even if some pClearValues entries between 0 and %u correspond to attachments "
+                "that aren't cleared they will be ignored.",
+                function_name, pRenderPassBegin->clearValueCount, clear_op_size,
+                device_data->report_data->FormatHandle(render_pass_state->renderPass).c_str(), clear_op_size, clear_op_size - 1);
         }
-        skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
-        skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, rp_version, cb_state, pRenderPassBegin,
-                                                      GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
+        skip |= VerifyRenderAreaBounds(device_data, pRenderPassBegin);
+        skip |= VerifyFramebufferAndRenderPassLayouts(device_data, rp_version, cb_state, pRenderPassBegin,
+                                                      GetFramebufferState(pRenderPassBegin->framebuffer));
         if (framebuffer->rp_state->renderPass != render_pass_state->renderPass) {
-            skip |= ValidateRenderPassCompatibility(dev_data, "render pass", render_pass_state, "framebuffer",
+            skip |= ValidateRenderPassCompatibility(device_data, "render pass", render_pass_state, "framebuffer",
                                                     framebuffer->rp_state.get(), function_name,
                                                     "VUID-VkRenderPassBeginInfo-renderPass-00904");
         }
 
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-renderpass" : "VUID-vkCmdBeginRenderPass-renderpass";
-        skip |= InsideRenderPass(dev_data, cb_state, function_name, vuid);
-        skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
+        skip |= InsideRenderPass(device_data, cb_state, function_name, vuid);
+        skip |= ValidateDependencies(device_data, framebuffer, render_pass_state);
 
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-bufferlevel" : "VUID-vkCmdBeginRenderPass-bufferlevel";
-        skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid);
+        skip |= ValidatePrimaryCommandBuffer(device_data, cb_state, function_name, vuid);
 
         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdBeginRenderPass-commandBuffer-cmdpool";
-        skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
+        skip |= ValidateCmdQueueFlags(device_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
 
         const CMD_TYPE cmd_type = use_rp2 ? CMD_BEGINRENDERPASS2KHR : CMD_BEGINRENDERPASS;
-        skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name);
+        skip |= ValidateCmd(device_data, cb_state, cmd_type, function_name);
     }
     return skip;
 }
 
-static void PreCallRecordCmdBeginRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
-                                            const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassContents contents) {
-    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
-    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
+bool CoreChecks::PreCallValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
+                                                   VkSubpassContents contents) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdBeginRenderPass(device_data, commandBuffer, RENDER_PASS_VERSION_1, pRenderPassBegin);
+    return skip;
+}
 
-    assert(cb_state);
+bool CoreChecks::PreCallValidateCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
+                                                       const VkSubpassBeginInfoKHR *pSubpassBeginInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdBeginRenderPass(device_data, commandBuffer, RENDER_PASS_VERSION_2, pRenderPassBegin);
+    return skip;
+}
+
+void CoreChecks::RecordCmdBeginRenderPassState(layer_data *device_data, VkCommandBuffer commandBuffer,
+                                               const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassContents contents) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(pRenderPassBegin->renderPass) : nullptr;
+    auto framebuffer = pRenderPassBegin ? GetFramebufferState(pRenderPassBegin->framebuffer) : nullptr;
+
     if (render_pass_state) {
         cb_state->activeFramebuffer = pRenderPassBegin->framebuffer;
         cb_state->activeRenderPass = render_pass_state;
@@ -10771,132 +10312,91 @@
         cb_state->activeSubpassContents = contents;
         cb_state->framebuffers.insert(pRenderPassBegin->framebuffer);
         // Connect this framebuffer and its children to this cmdBuffer
-        AddFramebufferBinding(dev_data, cb_state, framebuffer);
+        AddFramebufferBinding(device_data, cb_state, framebuffer);
         // Connect this RP to cmdBuffer
         AddCommandBufferBinding(&render_pass_state->cb_bindings,
                                 {HandleToUint64(render_pass_state->renderPass), kVulkanObjectTypeRenderPass}, cb_state);
         // transition attachments to the correct layouts for beginning of renderPass and first subpass
-        TransitionBeginRenderPassLayouts(dev_data, cb_state, render_pass_state, framebuffer);
+        TransitionBeginRenderPassLayouts(device_data, cb_state, render_pass_state, framebuffer);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
-                                              VkSubpassContents contents) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdBeginRenderPass(dev_data, cb_state, RENDER_PASS_VERSION_1, pRenderPassBegin);
-        if (!skip) {
-            PreCallRecordCmdBeginRenderPass(dev_data, cb_state, pRenderPassBegin, contents);
-        }
-    }
-
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
-    }
+void CoreChecks::PreCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
+                                                 VkSubpassContents contents) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdBeginRenderPassState(device_data, commandBuffer, pRenderPassBegin, contents);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
-                                                  const VkSubpassBeginInfoKHR *pSubpassBeginInfo) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        skip |= PreCallValidateCmdBeginRenderPass(dev_data, cb_state, RENDER_PASS_VERSION_2, pRenderPassBegin);
-        if (!skip) {
-            PreCallRecordCmdBeginRenderPass(dev_data, cb_state, pRenderPassBegin, pSubpassBeginInfo->contents);
-        }
-    }
-
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo->contents);
-    }
+void CoreChecks::PreCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
+                                                     const VkSubpassBeginInfoKHR *pSubpassBeginInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdBeginRenderPassState(device_data, commandBuffer, pRenderPassBegin, pSubpassBeginInfo->contents);
 }
 
-static bool PreCallValidateCmdNextSubpass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version,
-                                          VkCommandBuffer commandBuffer) {
+bool CoreChecks::ValidateCmdNextSubpass(layer_data *device_data, RenderPassCreateVersion rp_version,
+                                        VkCommandBuffer commandBuffer) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
     bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *vuid;
     const char *const function_name = use_rp2 ? "vkCmdNextSubpass2KHR()" : "vkCmdNextSubpass()";
 
     vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-bufferlevel" : "VUID-vkCmdNextSubpass-bufferlevel";
-    skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid);
+    skip |= ValidatePrimaryCommandBuffer(device_data, cb_state, function_name, vuid);
 
     vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdNextSubpass-commandBuffer-cmdpool";
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
     const CMD_TYPE cmd_type = use_rp2 ? CMD_NEXTSUBPASS2KHR : CMD_NEXTSUBPASS;
-    skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name);
+    skip |= ValidateCmd(device_data, cb_state, cmd_type, function_name);
 
     vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-renderpass" : "VUID-vkCmdNextSubpass-renderpass";
-    skip |= OutsideRenderPass(dev_data, cb_state, function_name, vuid);
+    skip |= OutsideRenderPass(device_data, cb_state, function_name, vuid);
 
     auto subpassCount = cb_state->activeRenderPass->createInfo.subpassCount;
     if (cb_state->activeSubpass == subpassCount - 1) {
         vuid = use_rp2 ? "VUID-vkCmdNextSubpass2KHR-None-03102" : "VUID-vkCmdNextSubpass-None-00909";
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), vuid, "%s: Attempted to advance beyond final subpass.", function_name);
     }
-
     return skip;
 }
 
-static void PostCallRecordCmdNextSubpass(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkSubpassContents contents) {
-    cb_node->activeSubpass++;
-    cb_node->activeSubpassContents = contents;
-    TransitionSubpassLayouts(dev_data, cb_node, cb_node->activeRenderPass, cb_node->activeSubpass,
-                             GetFramebufferState(dev_data, cb_node->activeRenderPassBeginInfo.framebuffer));
+bool CoreChecks::PreCallValidateCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    return ValidateCmdNextSubpass(device_data, RENDER_PASS_VERSION_1, commandBuffer);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdNextSubpass(dev_data, pCB, RENDER_PASS_VERSION_1, commandBuffer);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
-
-    if (pCB) {
-        lock.lock();
-        PostCallRecordCmdNextSubpass(dev_data, pCB, contents);
-    }
+bool CoreChecks::PreCallValidateCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR *pSubpassBeginInfo,
+                                                   const VkSubpassEndInfoKHR *pSubpassEndInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    return ValidateCmdNextSubpass(device_data, RENDER_PASS_VERSION_2, commandBuffer);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR *pSubpassBeginInfo,
-                                              const VkSubpassEndInfoKHR *pSubpassEndInfo) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdNextSubpass(dev_data, pCB, RENDER_PASS_VERSION_2, commandBuffer);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, pSubpassBeginInfo->contents);
-
-    if (pCB) {
-        lock.lock();
-        PostCallRecordCmdNextSubpass(dev_data, pCB, pSubpassBeginInfo->contents);
-    }
+void CoreChecks::RecordCmdNextSubpass(layer_data *device_data, VkCommandBuffer commandBuffer, VkSubpassContents contents) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    cb_state->activeSubpass++;
+    cb_state->activeSubpassContents = contents;
+    TransitionSubpassLayouts(device_data, cb_state, cb_state->activeRenderPass, cb_state->activeSubpass,
+                             GetFramebufferState(cb_state->activeRenderPassBeginInfo.framebuffer));
 }
-static bool PreCallValidateCmdEndRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, RenderPassCreateVersion rp_version,
-                                            VkCommandBuffer commandBuffer) {
-    bool skip = false;
 
+void CoreChecks::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdNextSubpass(device_data, commandBuffer, contents);
+}
+
+void CoreChecks::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR *pSubpassBeginInfo,
+                                                  const VkSubpassEndInfoKHR *pSubpassEndInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdNextSubpass(device_data, commandBuffer, pSubpassBeginInfo->contents);
+}
+
+bool CoreChecks::ValidateCmdEndRenderPass(layer_data *device_data, RenderPassCreateVersion rp_version,
+                                          VkCommandBuffer commandBuffer) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    bool skip = false;
     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
     const char *vuid;
     const char *const function_name = use_rp2 ? "vkCmdEndRenderPass2KHR()" : "vkCmdEndRenderPass()";
@@ -10905,75 +10405,58 @@
     if (rp_state) {
         if (cb_state->activeSubpass != rp_state->createInfo.subpassCount - 1) {
             vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-None-03103" : "VUID-vkCmdEndRenderPass-None-00910";
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), vuid, "%s: Called before reaching final subpass.", function_name);
         }
     }
 
     vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-renderpass" : "VUID-vkCmdEndRenderPass-renderpass";
-    skip |= OutsideRenderPass(dev_data, cb_state, function_name, vuid);
+    skip |= OutsideRenderPass(device_data, cb_state, function_name, vuid);
 
     vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-bufferlevel" : "VUID-vkCmdEndRenderPass-bufferlevel";
-    skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, function_name, vuid);
+    skip |= ValidatePrimaryCommandBuffer(device_data, cb_state, function_name, vuid);
 
     vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2KHR-commandBuffer-cmdpool" : "VUID-vkCmdEndRenderPass-commandBuffer-cmdpool";
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, function_name, VK_QUEUE_GRAPHICS_BIT, vuid);
 
     const CMD_TYPE cmd_type = use_rp2 ? CMD_ENDRENDERPASS2KHR : CMD_ENDRENDERPASS;
-    skip |= ValidateCmd(dev_data, cb_state, cmd_type, function_name);
+    skip |= ValidateCmd(device_data, cb_state, cmd_type, function_name);
     return skip;
 }
 
-static void PostCallRecordCmdEndRenderPass(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    FRAMEBUFFER_STATE *framebuffer = GetFramebufferState(dev_data, cb_state->activeFramebuffer);
-    TransitionFinalSubpassLayouts(dev_data, cb_state, &cb_state->activeRenderPassBeginInfo, framebuffer);
+bool CoreChecks::PreCallValidateCmdEndRenderPass(VkCommandBuffer commandBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdEndRenderPass(device_data, RENDER_PASS_VERSION_1, commandBuffer);
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR *pSubpassEndInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdEndRenderPass(device_data, RENDER_PASS_VERSION_2, commandBuffer);
+    return skip;
+}
+
+void CoreChecks::RecordCmdEndRenderPassState(layer_data *device_data, VkCommandBuffer commandBuffer) {
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    FRAMEBUFFER_STATE *framebuffer = GetFramebufferState(cb_state->activeFramebuffer);
+    TransitionFinalSubpassLayouts(device_data, cb_state, &cb_state->activeRenderPassBeginInfo, framebuffer);
     cb_state->activeRenderPass = nullptr;
     cb_state->activeSubpass = 0;
     cb_state->activeFramebuffer = VK_NULL_HANDLE;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdEndRenderPass(dev_data, pCB, RENDER_PASS_VERSION_1, commandBuffer);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
-
-    if (pCB) {
-        lock.lock();
-        PostCallRecordCmdEndRenderPass(dev_data, pCB);
-    }
+void CoreChecks::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdEndRenderPassState(device_data, commandBuffer);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR *pSubpassEndInfo) {
-    bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto pCB = GetCBNode(dev_data, commandBuffer);
-    if (pCB) {
-        skip |= PreCallValidateCmdEndRenderPass(dev_data, pCB, RENDER_PASS_VERSION_2, commandBuffer);
-    }
-    lock.unlock();
-
-    if (skip) return;
-
-    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
-
-    if (pCB) {
-        lock.lock();
-        PostCallRecordCmdEndRenderPass(dev_data, pCB);
-    }
+void CoreChecks::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR *pSubpassEndInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    RecordCmdEndRenderPassState(device_data, commandBuffer);
 }
 
-static bool ValidateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
-                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB, const char *caller) {
+bool CoreChecks::ValidateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
+                                     VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB, const char *caller) {
     bool skip = false;
     if (!pSubCB->beginInfo.pInheritanceInfo) {
         return skip;
@@ -10984,25 +10467,26 @@
         if (primary_fb != secondary_fb) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(primaryBuffer), "VUID-vkCmdExecuteCommands-pCommandBuffers-00099",
-                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64
-                            " which has a framebuffer 0x%" PRIx64
-                            " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ".",
-                            HandleToUint64(secondaryBuffer), HandleToUint64(secondary_fb), HandleToUint64(primary_fb));
+                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer %s which has a framebuffer %s"
+                            " that is not the same as the primary command buffer's current active framebuffer %s.",
+                            dev_data->report_data->FormatHandle(secondaryBuffer).c_str(),
+                            dev_data->report_data->FormatHandle(secondary_fb).c_str(),
+                            dev_data->report_data->FormatHandle(primary_fb).c_str());
         }
-        auto fb = GetFramebufferState(dev_data, secondary_fb);
+        auto fb = GetFramebufferState(secondary_fb);
         if (!fb) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(primaryBuffer), kVUID_Core_DrawState_InvalidSecondaryCommandBuffer,
-                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%" PRIx64
-                            " which has invalid framebuffer 0x%" PRIx64 ".",
-                            HandleToUint64(secondaryBuffer), HandleToUint64(secondary_fb));
+                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %s which has invalid framebuffer %s.",
+                            dev_data->report_data->FormatHandle(secondaryBuffer).c_str(),
+                            dev_data->report_data->FormatHandle(secondary_fb).c_str());
             return skip;
         }
     }
     return skip;
 }
 
-static bool ValidateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
+bool CoreChecks::ValidateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
     bool skip = false;
     unordered_set<int> activeTypes;
     for (auto queryObject : pCB->activeQueries) {
@@ -11015,10 +10499,10 @@
                     skip |= log_msg(
                         dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(pCB->commandBuffer), "VUID-vkCmdExecuteCommands-commandBuffer-00104",
-                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%" PRIx64
-                        " which has invalid active query pool 0x%" PRIx64
+                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %s which has invalid active query pool %s"
                         ". Pipeline statistics is being queried so the command buffer must have all bits set on the queryPool.",
-                        HandleToUint64(pCB->commandBuffer), HandleToUint64(queryPoolData->first));
+                        dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(),
+                        dev_data->report_data->FormatHandle(queryPoolData->first).c_str());
                 }
             }
             activeTypes.insert(queryPoolData->second.createInfo.queryType);
@@ -11029,61 +10513,68 @@
         if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidSecondaryCommandBuffer,
-                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%" PRIx64
-                            " which has invalid active query pool 0x%" PRIx64
-                            " of type %d but a query of that type has been started on secondary Cmd Buffer 0x%" PRIx64 ".",
-                            HandleToUint64(pCB->commandBuffer), HandleToUint64(queryPoolData->first),
-                            queryPoolData->second.createInfo.queryType, HandleToUint64(pSubCB->commandBuffer));
+                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %s which has invalid active query pool %s"
+                            " of type %d but a query of that type has been started on secondary Cmd Buffer %s.",
+                            dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(),
+                            dev_data->report_data->FormatHandle(queryPoolData->first).c_str(),
+                            queryPoolData->second.createInfo.queryType,
+                            dev_data->report_data->FormatHandle(pSubCB->commandBuffer).c_str());
         }
     }
 
-    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
-    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
+    auto primary_pool = GetCommandPoolNode(pCB->createInfo.commandPool);
+    auto secondary_pool = GetCommandPoolNode(pSubCB->createInfo.commandPool);
     if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(pSubCB->commandBuffer), kVUID_Core_DrawState_InvalidQueueFamily,
-                        "vkCmdExecuteCommands(): Primary command buffer 0x%" PRIx64
-                        " created in queue family %d has secondary command buffer 0x%" PRIx64 " created in queue family %d.",
-                        HandleToUint64(pCB->commandBuffer), primary_pool->queueFamilyIndex, HandleToUint64(pSubCB->commandBuffer),
-                        secondary_pool->queueFamilyIndex);
+                        "vkCmdExecuteCommands(): Primary command buffer %s created in queue family %d has secondary command buffer "
+                        "%s created in queue family %d.",
+                        dev_data->report_data->FormatHandle(pCB->commandBuffer).c_str(), primary_pool->queueFamilyIndex,
+                        dev_data->report_data->FormatHandle(pSubCB->commandBuffer).c_str(), secondary_pool->queueFamilyIndex);
     }
 
     return skip;
 }
 
-static bool PreCallValidateCmdExecuteCommands(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
-                                              uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) {
+bool CoreChecks::PreCallValidateCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
+                                                   const VkCommandBuffer *pCommandBuffers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
     bool skip = false;
     GLOBAL_CB_NODE *sub_cb_state = NULL;
+    std::unordered_set<GLOBAL_CB_NODE *> linked_command_buffers = cb_state->linkedCommandBuffers;
+
     for (uint32_t i = 0; i < commandBuffersCount; i++) {
-        sub_cb_state = GetCBNode(dev_data, pCommandBuffers[i]);
+        sub_cb_state = GetCBNode(pCommandBuffers[i]);
         assert(sub_cb_state);
         if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == sub_cb_state->createInfo.level) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCommandBuffers[i]), "VUID-vkCmdExecuteCommands-pCommandBuffers-00088",
-                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%" PRIx64
-                            " in element %u of pCommandBuffers array. All cmd buffers in pCommandBuffers array must be secondary.",
-                            HandleToUint64(pCommandBuffers[i]), i);
+                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %s in element %u of pCommandBuffers array. All "
+                            "cmd buffers in pCommandBuffers array must be secondary.",
+                            device_data->report_data->FormatHandle(pCommandBuffers[i]).c_str(), i);
         } else if (cb_state->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
             if (sub_cb_state->beginInfo.pInheritanceInfo != nullptr) {
-                auto secondary_rp_state = GetRenderPassState(dev_data, sub_cb_state->beginInfo.pInheritanceInfo->renderPass);
+                auto secondary_rp_state = GetRenderPassState(sub_cb_state->beginInfo.pInheritanceInfo->renderPass);
                 if (!(sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
-                    skip |= log_msg(
-                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                        HandleToUint64(pCommandBuffers[i]), "VUID-vkCmdExecuteCommands-pCommandBuffers-00096",
-                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%" PRIx64 ") executed within render pass (0x%" PRIx64
-                        ") must have had vkBeginCommandBuffer() called w/ "
-                        "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.",
-                        HandleToUint64(pCommandBuffers[i]), HandleToUint64(cb_state->activeRenderPass->renderPass));
+                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCommandBuffers[i]),
+                                    "VUID-vkCmdExecuteCommands-pCommandBuffers-00096",
+                                    "vkCmdExecuteCommands(): Secondary Command Buffer (%s) executed within render pass (%s) must "
+                                    "have had vkBeginCommandBuffer() called w/ "
+                                    "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.",
+                                    device_data->report_data->FormatHandle(pCommandBuffers[i]).c_str(),
+                                    device_data->report_data->FormatHandle(cb_state->activeRenderPass->renderPass).c_str());
                 } else {
                     // Make sure render pass is compatible with parent command buffer pass if has continue
                     if (cb_state->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
                         skip |= ValidateRenderPassCompatibility(
-                            dev_data, "primary command buffer", cb_state->activeRenderPass, "secondary command buffer",
+                            device_data, "primary command buffer", cb_state->activeRenderPass, "secondary command buffer",
                             secondary_rp_state, "vkCmdExecuteCommands()", "VUID-vkCmdExecuteCommands-pInheritanceInfo-00098");
                     }
                     //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
-                    skip |= ValidateFramebuffer(dev_data, commandBuffer, cb_state, pCommandBuffers[i], sub_cb_state,
+                    skip |= ValidateFramebuffer(device_data, commandBuffer, cb_state, pCommandBuffers[i], sub_cb_state,
                                                 "vkCmdExecuteCommands()");
                     if (!sub_cb_state->cmd_execute_commands_functions.empty()) {
                         //  Inherit primary's activeFramebuffer and while running validate functions
@@ -11095,44 +10586,40 @@
             }
         }
         // TODO(mlentine): Move more logic into this method
-        skip |= ValidateSecondaryCommandBufferState(dev_data, cb_state, sub_cb_state);
-        skip |= ValidateCommandBufferState(dev_data, sub_cb_state, "vkCmdExecuteCommands()", 0,
+        skip |= ValidateSecondaryCommandBufferState(device_data, cb_state, sub_cb_state);
+        skip |= ValidateCommandBufferState(device_data, sub_cb_state, "vkCmdExecuteCommands()", 0,
                                            "VUID-vkCmdExecuteCommands-pCommandBuffers-00089");
         if (!(sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
-            if (sub_cb_state->in_use.load() || cb_state->linkedCommandBuffers.count(sub_cb_state)) {
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdExecuteCommands-pCommandBuffers-00090",
-                            "Attempt to simultaneously execute command buffer 0x%" PRIx64
-                            " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set!",
-                            HandleToUint64(cb_state->commandBuffer));
+            if (sub_cb_state->in_use.load() || linked_command_buffers.count(sub_cb_state)) {
+                skip |= log_msg(
+                    device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    HandleToUint64(cb_state->commandBuffer), "VUID-vkCmdExecuteCommands-pCommandBuffers-00090",
+                    "Attempt to simultaneously execute command buffer %s without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set!",
+                    device_data->report_data->FormatHandle(cb_state->commandBuffer).c_str());
             }
             if (cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
                 // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            HandleToUint64(pCommandBuffers[i]), kVUID_Core_DrawState_InvalidCommandBufferSimultaneousUse,
-                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%" PRIx64
-                            ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary "
-                            "command buffer (0x%" PRIx64
-                            ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set, even "
-                            "though it does.",
-                            HandleToUint64(pCommandBuffers[i]), HandleToUint64(cb_state->commandBuffer));
-                // TODO: Clearing the VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT needs to be moved from the validation step to the
-                // recording step
-                cb_state->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
+                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCommandBuffers[i]),
+                                kVUID_Core_DrawState_InvalidCommandBufferSimultaneousUse,
+                                "vkCmdExecuteCommands(): Secondary Command Buffer (%s) does not have "
+                                "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary "
+                                "command buffer (%s) to be treated as if it does not have "
+                                "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set, even though it does.",
+                                device_data->report_data->FormatHandle(pCommandBuffers[i]).c_str(),
+                                device_data->report_data->FormatHandle(cb_state->commandBuffer).c_str());
             }
         }
-        if (!cb_state->activeQueries.empty() && !dev_data->enabled_features.core.inheritedQueries) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        if (!cb_state->activeQueries.empty() && !device_data->enabled_features.core.inheritedQueries) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCommandBuffers[i]), "VUID-vkCmdExecuteCommands-commandBuffer-00101",
-                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%" PRIx64
-                            ") cannot be submitted with a query in flight and inherited queries not supported on this device.",
-                            HandleToUint64(pCommandBuffers[i]));
+                            "vkCmdExecuteCommands(): Secondary Command Buffer (%s) cannot be submitted with a query in flight and "
+                            "inherited queries not supported on this device.",
+                            device_data->report_data->FormatHandle(pCommandBuffers[i]).c_str());
         }
         // Propagate layout transitions to the primary cmd buffer
         // Novel Valid usage: "UNASSIGNED-vkCmdExecuteCommands-commandBuffer-00001"
-        //  initial layout usage of secondary command buffers resources must match parent command buffer
+        // initial layout usage of secondary command buffers resources must match parent command buffer
         for (const auto &ilm_entry : sub_cb_state->imageLayoutMap) {
             auto cb_entry = cb_state->imageLayoutMap.find(ilm_entry.first);
             if (cb_entry != cb_state->imageLayoutMap.end()) {
@@ -11140,55 +10627,56 @@
                 if ((VK_IMAGE_LAYOUT_UNDEFINED != ilm_entry.second.initialLayout) &&
                     (cb_entry->second.layout != ilm_entry.second.initialLayout)) {
                     const VkImageSubresource &subresource = ilm_entry.first.subresource;
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(pCommandBuffers[i]), "UNASSIGNED-vkCmdExecuteCommands-commandBuffer-00001",
-                            "%s: Cannot execute cmd buffer using image (0x%" PRIx64
-                            ") [sub-resource: aspectMask 0x%X "
-                            "array layer %u, mip level %u], with current layout %s when first use is %s.",
-                            "vkCmdExecuteCommands():", HandleToUint64(ilm_entry.first.image), subresource.aspectMask,
-                            subresource.arrayLayer, subresource.mipLevel, string_VkImageLayout(cb_entry->second.layout),
-                            string_VkImageLayout(ilm_entry.second.initialLayout));
+                            "%s: Executed secondary command buffer using image %s (subresource: aspectMask 0x%X array layer %u, "
+                            "mip level %u) which expects layout %s--instead, image %s's current layout is %s.",
+                            "vkCmdExecuteCommands():", device_data->report_data->FormatHandle(ilm_entry.first.image).c_str(),
+                            subresource.aspectMask, subresource.arrayLayer, subresource.mipLevel,
+                            string_VkImageLayout(ilm_entry.second.initialLayout),
+                            device_data->report_data->FormatHandle(ilm_entry.first.image).c_str(),
+                            string_VkImageLayout(cb_entry->second.layout));
                 }
             } else {
                 // Look for partial matches (in aspectMask), and update or create parent map entry in SetLayout
                 assert(ilm_entry.first.hasSubresource);
                 IMAGE_CMD_BUF_LAYOUT_NODE node;
-                if (FindCmdBufLayout(dev_data, cb_state, ilm_entry.first.image, ilm_entry.first.subresource, node)) {
+                if (FindCmdBufLayout(device_data, cb_state, ilm_entry.first.image, ilm_entry.first.subresource, node)) {
                     if ((VK_IMAGE_LAYOUT_UNDEFINED != ilm_entry.second.initialLayout) &&
                         (node.layout != ilm_entry.second.initialLayout)) {
                         const VkImageSubresource &subresource = ilm_entry.first.subresource;
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCommandBuffers[i]),
                                 "UNASSIGNED-vkCmdExecuteCommands-commandBuffer-00001",
-                                "%s: Cannot execute cmd buffer using image (0x%" PRIx64
-                                ") [sub-resource: aspectMask 0x%X "
-                                "array layer %u, mip level %u], with current layout %s when first use is %s.",
-                                "vkCmdExecuteCommands():", HandleToUint64(ilm_entry.first.image), subresource.aspectMask,
-                                subresource.arrayLayer, subresource.mipLevel, string_VkImageLayout(node.layout),
-                                string_VkImageLayout(ilm_entry.second.initialLayout));
+                                "%s: Executed secondary command buffer using image %s (subresource: aspectMask 0x%X array layer "
+                                "%u, mip level %u) which expects layout %s--instead, image %s's current layout is %s.",
+                                "vkCmdExecuteCommands():", device_data->report_data->FormatHandle(ilm_entry.first.image).c_str(),
+                                subresource.aspectMask, subresource.arrayLayer, subresource.mipLevel,
+                                string_VkImageLayout(ilm_entry.second.initialLayout),
+                                device_data->report_data->FormatHandle(ilm_entry.first.image).c_str(),
+                                string_VkImageLayout(node.layout));
                     }
                 }
             }
         }
-        // TODO: Linking command buffers here is necessary to pass existing validation tests--however, this state change still needs
-        // to be removed from the validation step
-        sub_cb_state->primaryCommandBuffer = cb_state->commandBuffer;
-        cb_state->linkedCommandBuffers.insert(sub_cb_state);
-        sub_cb_state->linkedCommandBuffers.insert(cb_state);
+        linked_command_buffers.insert(sub_cb_state);
     }
-    skip |= ValidatePrimaryCommandBuffer(dev_data, cb_state, "vkCmdExecuteCommands()", "VUID-vkCmdExecuteCommands-bufferlevel");
-    skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdExecuteCommands()",
+    skip |= ValidatePrimaryCommandBuffer(device_data, cb_state, "vkCmdExecuteCommands()", "VUID-vkCmdExecuteCommands-bufferlevel");
+    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdExecuteCommands()",
                                   VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
                                   "VUID-vkCmdExecuteCommands-commandBuffer-cmdpool");
-    skip |= ValidateCmd(dev_data, cb_state, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
+    skip |= ValidateCmd(device_data, cb_state, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
     return skip;
 }
 
-static void PreCallRecordCmdExecuteCommands(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, uint32_t commandBuffersCount,
-                                            const VkCommandBuffer *pCommandBuffers) {
+void CoreChecks::PreCallRecordCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
+                                                 const VkCommandBuffer *pCommandBuffers) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+
     GLOBAL_CB_NODE *sub_cb_state = NULL;
     for (uint32_t i = 0; i < commandBuffersCount; i++) {
-        sub_cb_state = GetCBNode(dev_data, pCommandBuffers[i]);
+        sub_cb_state = GetCBNode(pCommandBuffers[i]);
         assert(sub_cb_state);
         if (!(sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
             if (cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
@@ -11209,11 +10697,11 @@
                 // Look for partial matches (in aspectMask), and update or create parent map entry in SetLayout
                 assert(ilm_entry.first.hasSubresource);
                 IMAGE_CMD_BUF_LAYOUT_NODE node;
-                if (!FindCmdBufLayout(dev_data, cb_state, ilm_entry.first.image, ilm_entry.first.subresource, node)) {
+                if (!FindCmdBufLayout(device_data, cb_state, ilm_entry.first.image, ilm_entry.first.subresource, node)) {
                     node.initialLayout = ilm_entry.second.initialLayout;
                 }
                 node.layout = ilm_entry.second.layout;
-                SetLayout(dev_data, cb_state, ilm_entry.first, node);
+                SetLayout(device_data, cb_state, ilm_entry.first, node);
             }
         }
         sub_cb_state->primaryCommandBuffer = cb_state->commandBuffer;
@@ -11228,77 +10716,51 @@
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
-                                              const VkCommandBuffer *pCommandBuffers) {
+bool CoreChecks::PreCallValidateMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
+                                          VkFlags flags, void **ppData) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    if (cb_state) {
-        // TODO: State changes needs to be untangled from validation in PreCallValidationCmdExecuteCommands()
-        skip |= PreCallValidateCmdExecuteCommands(dev_data, cb_state, commandBuffer, commandBuffersCount, pCommandBuffers);
-        PreCallRecordCmdExecuteCommands(dev_data, cb_state, commandBuffersCount, pCommandBuffers);
-    }
-    lock.unlock();
-    if (!skip) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
-}
-
-static bool PreCallValidateMapMemory(layer_data *dev_data, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset,
-                                     VkDeviceSize size) {
-    bool skip = false;
-    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
+    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(mem);
     if (mem_info) {
         auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
-        skip |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
-        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
+        skip |= ValidateMapImageLayouts(device_data, device, mem_info, offset, end_offset);
+        if ((device_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
              VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
-            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
+            skip = log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                            HandleToUint64(mem), "VUID-vkMapMemory-memory-00682",
-                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIx64 ".",
-                           HandleToUint64(mem));
+                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %s.",
+                           device_data->report_data->FormatHandle(mem).c_str());
         }
     }
-    skip |= ValidateMapMemRange(dev_data, mem, offset, size);
+    skip |= ValidateMapMemRange(device_data, mem, offset, size);
     return skip;
 }
 
-static void PostCallRecordMapMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
-                                    void **ppData) {
+void CoreChecks::PostCallRecordMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
+                                         void **ppData, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
     // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
-    StoreMemRanges(dev_data, mem, offset, size);
-    InitializeAndTrackMemory(dev_data, mem, offset, size, ppData);
+    StoreMemRanges(device_data, mem, offset, size);
+    InitializeAndTrackMemory(device_data, mem, offset, size, ppData);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
-                                         void **ppData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateMapMemory(dev_data, device, mem, offset, size);
-    lock.unlock();
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    if (!skip) {
-        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
-        if (VK_SUCCESS == result) {
-            lock.lock();
-            PostCallRecordMapMemory(dev_data, mem, offset, size, ppData);
-            lock.unlock();
-        }
-    }
-    return result;
-}
-
-static bool PreCallValidateUnmapMemory(const layer_data *dev_data, DEVICE_MEM_INFO *mem_info, const VkDeviceMemory mem) {
+bool CoreChecks::PreCallValidateUnmapMemory(VkDevice device, VkDeviceMemory mem) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    if (!mem_info->mem_range.size) {
+    auto mem_info = GetMemObjInfo(mem);
+    if (mem_info && !mem_info->mem_range.size) {
         // Valid Usage: memory must currently be mapped
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                         HandleToUint64(mem), "VUID-vkUnmapMemory-memory-00689",
-                        "Unmapping Memory without memory being mapped: mem obj 0x%" PRIx64 ".", HandleToUint64(mem));
+                        "Unmapping Memory without memory being mapped: mem obj %s.",
+                        device_data->report_data->FormatHandle(mem).c_str());
     }
     return skip;
 }
 
-static void PreCallRecordUnmapMemory(DEVICE_MEM_INFO *mem_info) {
+void CoreChecks::PreCallRecordUnmapMemory(VkDevice device, VkDeviceMemory mem) {
+    auto mem_info = GetMemObjInfo(mem);
     mem_info->mem_range.size = 0;
     if (mem_info->shadow_copy) {
         free(mem_info->shadow_copy_base);
@@ -11307,26 +10769,11 @@
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = false;
-    unique_lock_t lock(global_lock);
-    auto mem_info = GetMemObjInfo(dev_data, mem);
-    if (mem_info) {
-        skip |= PreCallValidateUnmapMemory(dev_data, mem_info, mem);
-        PreCallRecordUnmapMemory(mem_info);
-    }
-    lock.unlock();
-    if (!skip) {
-        dev_data->dispatch_table.UnmapMemory(device, mem);
-    }
-}
-
-static bool ValidateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
-                                   const VkMappedMemoryRange *pMemRanges) {
+bool CoreChecks::ValidateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
+                                        const VkMappedMemoryRange *pMemRanges) {
     bool skip = false;
     for (uint32_t i = 0; i < memRangeCount; ++i) {
-        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
+        auto mem_info = GetMemObjInfo(pMemRanges[i].memory);
         if (mem_info) {
             if (pMemRanges[i].size == VK_WHOLE_SIZE) {
                 if (mem_info->mem_range.offset > pMemRanges[i].offset) {
@@ -11357,11 +10804,11 @@
     return skip;
 }
 
-static bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
-                                                     const VkMappedMemoryRange *mem_ranges) {
+bool CoreChecks::ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
+                                                          const VkMappedMemoryRange *mem_ranges) {
     bool skip = false;
     for (uint32_t i = 0; i < mem_range_count; ++i) {
-        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
+        auto mem_info = GetMemObjInfo(mem_ranges[i].memory);
         if (mem_info) {
             if (mem_info->shadow_copy) {
                 VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
@@ -11372,16 +10819,16 @@
                     if (data[j] != NoncoherentMemoryFillValue) {
                         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                         VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, HandleToUint64(mem_ranges[i].memory),
-                                        kVUID_Core_MemTrack_InvalidMap, "Memory underflow was detected on mem obj 0x%" PRIx64,
-                                        HandleToUint64(mem_ranges[i].memory));
+                                        kVUID_Core_MemTrack_InvalidMap, "Memory underflow was detected on mem obj %s.",
+                                        dev_data->report_data->FormatHandle(mem_ranges[i].memory).c_str());
                     }
                 }
                 for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
                     if (data[j] != NoncoherentMemoryFillValue) {
                         skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                         VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, HandleToUint64(mem_ranges[i].memory),
-                                        kVUID_Core_MemTrack_InvalidMap, "Memory overflow was detected on mem obj 0x%" PRIx64,
-                                        HandleToUint64(mem_ranges[i].memory));
+                                        kVUID_Core_MemTrack_InvalidMap, "Memory overflow was detected on mem obj %s.",
+                                        dev_data->report_data->FormatHandle(mem_ranges[i].memory).c_str());
                     }
                 }
                 memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
@@ -11391,9 +10838,10 @@
     return skip;
 }
 
-static void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
+void CoreChecks::CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count,
+                                                 const VkMappedMemoryRange *mem_ranges) {
     for (uint32_t i = 0; i < mem_range_count; ++i) {
-        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
+        auto mem_info = GetMemObjInfo(mem_ranges[i].memory);
         if (mem_info && mem_info->shadow_copy) {
             VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
                                     ? mem_info->mem_range.size
@@ -11404,11 +10852,11 @@
     }
 }
 
-static bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
-                                                  const VkMappedMemoryRange *mem_ranges) {
+bool CoreChecks::ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
+                                                       const VkMappedMemoryRange *mem_ranges) {
     bool skip = false;
     for (uint32_t i = 0; i < mem_range_count; ++i) {
-        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
+        uint64_t atom_size = dev_data->phys_dev_props.limits.nonCoherentAtomSize;
         if (SafeModulo(mem_ranges[i].offset, atom_size) != 0) {
             skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
                             HandleToUint64(mem_ranges->memory), "VUID-VkMappedMemoryRange-offset-00687",
@@ -11416,7 +10864,7 @@
                             ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 ").",
                             func_name, i, mem_ranges[i].offset, atom_size);
         }
-        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
+        auto mem_info = GetMemObjInfo(mem_ranges[i].memory);
         if ((mem_ranges[i].size != VK_WHOLE_SIZE) &&
             (mem_ranges[i].size + mem_ranges[i].offset != mem_info->alloc_info.allocationSize) &&
             (SafeModulo(mem_ranges[i].size, atom_size) != 0)) {
@@ -11430,92 +10878,83 @@
     return skip;
 }
 
-static bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
-                                                   const VkMappedMemoryRange *mem_ranges) {
+bool CoreChecks::PreCallValidateFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
+                                                        const VkMappedMemoryRange *pMemRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    lock_guard_t lock(global_lock);
-    skip |= ValidateMappedMemoryRangeDeviceLimits(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
-    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
-    skip |= ValidateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
+    skip |= ValidateMappedMemoryRangeDeviceLimits(device_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
+    skip |= ValidateAndCopyNoncoherentMemoryToDriver(device_data, memRangeCount, pMemRanges);
+    skip |= ValidateMemoryIsMapped(device_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
-                                                       const VkMappedMemoryRange *pMemRanges) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool CoreChecks::PreCallValidateInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
+                                                             const VkMappedMemoryRange *pMemRanges) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    skip |= ValidateMappedMemoryRangeDeviceLimits(device_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
+    skip |= ValidateMemoryIsMapped(device_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
+    return skip;
+}
 
-    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
-        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
+void CoreChecks::PostCallRecordInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
+                                                            const VkMappedMemoryRange *pMemRanges, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS == result) {
+        // Update our shadow copy with modified driver data
+        CopyNoncoherentMemoryFromDriver(device_data, memRangeCount, pMemRanges);
     }
-    return result;
 }
 
-static bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
-                                                        const VkMappedMemoryRange *mem_ranges) {
-    bool skip = false;
-    lock_guard_t lock(global_lock);
-    skip |= ValidateMappedMemoryRangeDeviceLimits(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
-    skip |= ValidateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
-    return skip;
-}
-
-static void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
-                                                       const VkMappedMemoryRange *mem_ranges) {
-    lock_guard_t lock(global_lock);
-    // Update our shadow copy with modified driver data
-    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
-                                                            const VkMappedMemoryRange *pMemRanges) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+bool CoreChecks::PreCallValidateGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory mem, VkDeviceSize *pCommittedMem) {
     layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    auto mem_info = GetMemObjInfo(mem);
 
-    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
-        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
-        if (result == VK_SUCCESS) {
-            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
+    if (mem_info) {
+        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
+             VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) == 0) {
+            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
+                           HandleToUint64(mem), "VUID-vkGetDeviceMemoryCommitment-memory-00690",
+                           "Querying commitment for memory without VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT set: mem obj %s.",
+                           dev_data->report_data->FormatHandle(mem).c_str());
         }
     }
-    return result;
+    return skip;
 }
 
-static bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
-                                           VkDeviceSize memoryOffset, const char *api_name) {
+bool CoreChecks::ValidateBindImageMemory(layer_data *device_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                         const char *api_name) {
     bool skip = false;
+    IMAGE_STATE *image_state = GetImageState(image);
     if (image_state) {
-        unique_lock_t lock(global_lock);
         // Track objects tied to memory
         uint64_t image_handle = HandleToUint64(image);
-        skip = ValidateSetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, api_name);
+        skip = ValidateSetMemBinding(device_data, mem, image_handle, kVulkanObjectTypeImage, api_name);
         if (!image_state->memory_requirements_checked) {
             // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
             // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
             // vkGetImageMemoryRequirements()
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             image_handle, kVUID_Core_DrawState_InvalidImage,
-                            "%s: Binding memory to image 0x%" PRIx64
-                            " but vkGetImageMemoryRequirements() has not been called on that image.",
-                            api_name, HandleToUint64(image_handle));
+                            "%s: Binding memory to image %s but vkGetImageMemoryRequirements() has not been called on that image.",
+                            api_name, device_data->report_data->FormatHandle(image_handle).c_str());
             // Make the call for them so we can verify the state
-            lock.unlock();
-            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
-            lock.lock();
+            device_data->device_dispatch_table.GetImageMemoryRequirements(device_data->device, image, &image_state->requirements);
         }
 
         // Validate bound memory range information
-        auto mem_info = GetMemObjInfo(dev_data, mem);
+        auto mem_info = GetMemObjInfo(mem);
         if (mem_info) {
-            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
+            skip |= ValidateInsertImageMemoryRange(device_data, image, mem_info, memoryOffset, image_state->requirements,
                                                    image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, api_name);
-            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, api_name,
+            skip |= ValidateMemoryTypes(device_data, mem_info, image_state->requirements.memoryTypeBits, api_name,
                                         "VUID-vkBindImageMemory-memory-01047");
         }
 
         // Validate memory requirements alignment
         if (SafeModulo(memoryOffset, image_state->requirements.alignment) != 0) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                             image_handle, "VUID-vkBindImageMemory-memoryOffset-01048",
                             "%s: memoryOffset is 0x%" PRIxLEAST64
                             " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
@@ -11526,7 +10965,7 @@
         if (mem_info) {
             // Validate memory requirements size
             if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
-                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                 image_handle, "VUID-vkBindImageMemory-size-01049",
                                 "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64
                                 " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
@@ -11541,129 +10980,117 @@
                 if (strcmp(api_name, "vkBindImageMemory()") == 0) {
                     validation_error = "VUID-vkBindImageMemory-memory-01509";
                 }
-                skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
-                            image_handle, validation_error,
-                            "%s: for dedicated memory allocation 0x%" PRIxLEAST64
-                            ", VkMemoryDedicatedAllocateInfoKHR::image 0x%" PRIXLEAST64 " must be equal to image 0x%" PRIxLEAST64
-                            " and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
-                            api_name, HandleToUint64(mem), HandleToUint64(mem_info->dedicated_image), image_handle, memoryOffset);
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                                image_handle, validation_error,
+                                "%s: for dedicated memory allocation %s, VkMemoryDedicatedAllocateInfoKHR::image %s must be equal "
+                                "to image %s and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
+                                api_name, device_data->report_data->FormatHandle(mem).c_str(),
+                                device_data->report_data->FormatHandle(mem_info->dedicated_image).c_str(),
+                                device_data->report_data->FormatHandle(image_handle).c_str(), memoryOffset);
             }
         }
     }
     return skip;
 }
 
-static void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
-                                          VkDeviceSize memoryOffset, const char *api_name) {
+bool CoreChecks::PreCallValidateBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateBindImageMemory(device_data, image, mem, memoryOffset, "vkBindImageMemory()");
+}
+
+void CoreChecks::UpdateBindImageMemoryState(layer_data *device_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
+    IMAGE_STATE *image_state = GetImageState(image);
     if (image_state) {
-        unique_lock_t lock(global_lock);
         // Track bound memory range information
-        auto mem_info = GetMemObjInfo(dev_data, mem);
+        auto mem_info = GetMemObjInfo(mem);
         if (mem_info) {
-            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
+            InsertImageMemoryRange(device_data, image, mem_info, memoryOffset, image_state->requirements,
                                    image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
         }
 
         // Track objects tied to memory
         uint64_t image_handle = HandleToUint64(image);
-        SetMemBinding(dev_data, mem, image_state, memoryOffset, image_handle, kVulkanObjectTypeImage, api_name);
+        SetMemBinding(device_data, mem, image_state, memoryOffset, image_handle, kVulkanObjectTypeImage);
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    IMAGE_STATE *image_state;
-    {
-        unique_lock_t lock(global_lock);
-        image_state = GetImageState(dev_data, image);
-    }
-    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset, "vkBindImageMemory()");
-    if (!skip) {
-        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset, "vkBindImageMemory()");
-        }
-    }
-    return result;
+void CoreChecks::PostCallRecordBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                               VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    UpdateBindImageMemoryState(device_data, image, mem, memoryOffset);
 }
 
-static bool PreCallValidateBindImageMemory2(layer_data *dev_data, std::vector<IMAGE_STATE *> *image_state, uint32_t bindInfoCount,
-                                            const VkBindImageMemoryInfoKHR *pBindInfos) {
-    {
-        unique_lock_t lock(global_lock);
-        for (uint32_t i = 0; i < bindInfoCount; i++) {
-            (*image_state)[i] = GetImageState(dev_data, pBindInfos[i].image);
-        }
-    }
+bool CoreChecks::PreCallValidateBindImageMemory2(VkDevice device, uint32_t bindInfoCount,
+                                                 const VkBindImageMemoryInfoKHR *pBindInfos) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
     char api_name[128];
     for (uint32_t i = 0; i < bindInfoCount; i++) {
         sprintf(api_name, "vkBindImageMemory2() pBindInfos[%u]", i);
-        skip |= PreCallValidateBindImageMemory(dev_data, pBindInfos[i].image, (*image_state)[i], pBindInfos[i].memory,
-                                               pBindInfos[i].memoryOffset, api_name);
+        skip |=
+            ValidateBindImageMemory(device_data, pBindInfos[i].image, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
     }
     return skip;
 }
 
-static void PostCallRecordBindImageMemory2(layer_data *dev_data, const std::vector<IMAGE_STATE *> &image_state,
-                                           uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR *pBindInfos) {
-    for (uint32_t i = 0; i < bindInfoCount; i++) {
-        PostCallRecordBindImageMemory(dev_data, pBindInfos[i].image, image_state[i], pBindInfos[i].memory,
-                                      pBindInfos[i].memoryOffset, "vkBindImageMemory2()");
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
-                                                const VkBindImageMemoryInfoKHR *pBindInfos) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::vector<IMAGE_STATE *> image_state(bindInfoCount);
-    if (!PreCallValidateBindImageMemory2(dev_data, &image_state, bindInfoCount, pBindInfos)) {
-        result = dev_data->dispatch_table.BindImageMemory2(device, bindInfoCount, pBindInfos);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindImageMemory2(dev_data, image_state, bindInfoCount, pBindInfos);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount,
-                                                   const VkBindImageMemoryInfoKHR *pBindInfos) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::vector<IMAGE_STATE *> image_state(bindInfoCount);
-    if (!PreCallValidateBindImageMemory2(dev_data, &image_state, bindInfoCount, pBindInfos)) {
-        result = dev_data->dispatch_table.BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
-        if (result == VK_SUCCESS) {
-            PostCallRecordBindImageMemory2(dev_data, image_state, bindInfoCount, pBindInfos);
-        }
-    }
-    return result;
-}
-
-static bool PreCallValidateSetEvent(layer_data *dev_data, VkEvent event) {
+bool CoreChecks::PreCallValidateBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount,
+                                                    const VkBindImageMemoryInfoKHR *pBindInfos) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
-    auto event_state = GetEventNode(dev_data, event);
+    char api_name[128];
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        sprintf(api_name, "vkBindImageMemory2KHR() pBindInfos[%u]", i);
+        skip |=
+            ValidateBindImageMemory(device_data, pBindInfos[i].image, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
+    }
+    return skip;
+}
+
+void CoreChecks::PostCallRecordBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR *pBindInfos,
+                                                VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        UpdateBindImageMemoryState(device_data, pBindInfos[i].image, pBindInfos[i].memory, pBindInfos[i].memoryOffset);
+    }
+}
+
+void CoreChecks::PostCallRecordBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount,
+                                                   const VkBindImageMemoryInfoKHR *pBindInfos, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    for (uint32_t i = 0; i < bindInfoCount; i++) {
+        UpdateBindImageMemoryState(device_data, pBindInfos[i].image, pBindInfos[i].memory, pBindInfos[i].memoryOffset);
+    }
+}
+
+bool CoreChecks::PreCallValidateSetEvent(VkDevice device, VkEvent event) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    auto event_state = GetEventNode(event);
+    if (event_state) {
+        if (event_state->write_in_use) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
+                            HandleToUint64(event), kVUID_Core_DrawState_QueueForwardProgress,
+                            "Cannot call vkSetEvent() on event %s that is already in use by a command buffer.",
+                            device_data->report_data->FormatHandle(event).c_str());
+        }
+    }
+    return skip;
+}
+
+void CoreChecks::PreCallRecordSetEvent(VkDevice device, VkEvent event) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto event_state = GetEventNode(event);
     if (event_state) {
         event_state->needsSignaled = false;
         event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
-        if (event_state->write_in_use) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
-                            HandleToUint64(event), kVUID_Core_DrawState_QueueForwardProgress,
-                            "Cannot call vkSetEvent() on event 0x%" PRIx64 " that is already in use by a command buffer.",
-                            HandleToUint64(event));
-        }
     }
-    return skip;
-}
-
-static void PreCallRecordSetEvent(layer_data *dev_data, VkEvent event) {
     // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
     // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
     // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
-    for (auto queue_data : dev_data->queueMap) {
+    for (auto queue_data : device_data->queueMap) {
         auto event_entry = queue_data.second.eventToStageMap.find(event);
         if (event_entry != queue_data.second.eventToStageMap.end()) {
             event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
@@ -11671,23 +11098,11 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateSetEvent(dev_data, event);
-    PreCallRecordSetEvent(dev_data, event);
-    lock.unlock();
-
-    if (!skip) result = dev_data->dispatch_table.SetEvent(device, event);
-    return result;
-}
-
-static bool PreCallValidateQueueBindSparse(layer_data *dev_data, VkQueue queue, uint32_t bindInfoCount,
-                                           const VkBindSparseInfo *pBindInfo, VkFence fence) {
-    auto pFence = GetFenceNode(dev_data, fence);
-    bool skip = ValidateFenceForSubmit(dev_data, pFence);
+bool CoreChecks::PreCallValidateQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
+                                                VkFence fence) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    auto pFence = GetFenceNode(fence);
+    bool skip = ValidateFenceForSubmit(device_data, pFence);
     if (skip) {
         return true;
     }
@@ -11702,14 +11117,16 @@
         std::vector<VkSemaphore> semaphore_signals;
         for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
             VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore && (pSemaphore->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
                 if (unsignaled_semaphores.count(semaphore) ||
                     (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                    HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                    "Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
-                                    HandleToUint64(queue), HandleToUint64(semaphore));
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
+                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
+                                "Queue %s is waiting on semaphore %s that has no way to be signaled.",
+                                device_data->report_data->FormatHandle(queue).c_str(),
+                                device_data->report_data->FormatHandle(semaphore).c_str());
                 } else {
                     signaled_semaphores.erase(semaphore);
                     unsignaled_semaphores.insert(semaphore);
@@ -11721,15 +11138,17 @@
         }
         for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
             VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore && pSemaphore->scope == kSyncScopeInternal) {
                 if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
-                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                    HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                    "Queue 0x%" PRIx64 " is signaling semaphore 0x%" PRIx64
-                                    " that was previously signaled by queue 0x%" PRIx64
-                                    " but has not since been waited on by any queue.",
-                                    HandleToUint64(queue), HandleToUint64(semaphore), HandleToUint64(pSemaphore->signaler.first));
+                    skip |=
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
+                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
+                                "Queue %s is signaling semaphore %s that was previously signaled by queue %s but has not since "
+                                "been waited on by any queue.",
+                                device_data->report_data->FormatHandle(queue).c_str(),
+                                device_data->report_data->FormatHandle(semaphore).c_str(),
+                                device_data->report_data->FormatHandle(pSemaphore->signaler.first).c_str());
                 } else {
                     unsignaled_semaphores.erase(semaphore);
                     signaled_semaphores.insert(semaphore);
@@ -11741,57 +11160,80 @@
         // If we're binding sparse image memory make sure reqs were queried and note if metadata is required and bound
         for (uint32_t i = 0; i < bindInfo.imageBindCount; ++i) {
             const auto &image_bind = bindInfo.pImageBinds[i];
-            auto image_state = GetImageState(dev_data, image_bind.image);
+            auto image_state = GetImageState(image_bind.image);
             if (!image_state)
                 continue;  // Param/Object validation should report image_bind.image handles being invalid, so just skip here.
             sparse_images.insert(image_state);
-            if (!image_state->get_sparse_reqs_called || image_state->sparse_requirements.empty()) {
-                // For now just warning if sparse image binding occurs without calling to get reqs first
-                return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-                               HandleToUint64(image_state->image), kVUID_Core_MemTrack_InvalidState,
-                               "vkQueueBindSparse(): Binding sparse memory to image 0x%" PRIx64
-                               " without first calling vkGetImageSparseMemoryRequirements[2KHR]() to retrieve requirements.",
-                               HandleToUint64(image_state->image));
-            }
-            for (uint32_t j = 0; j < image_bind.bindCount; ++j) {
-                if (image_bind.pBinds[j].flags & VK_IMAGE_ASPECT_METADATA_BIT) {
-                    image_state->sparse_metadata_bound = true;
+            if (image_state->createInfo.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) {
+                if (!image_state->get_sparse_reqs_called || image_state->sparse_requirements.empty()) {
+                    // For now just warning if sparse image binding occurs without calling to get reqs first
+                    return log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                                   HandleToUint64(image_state->image), kVUID_Core_MemTrack_InvalidState,
+                                   "vkQueueBindSparse(): Binding sparse memory to image %s without first calling "
+                                   "vkGetImageSparseMemoryRequirements[2KHR]() to retrieve requirements.",
+                                   device_data->report_data->FormatHandle(image_state->image).c_str());
                 }
             }
+            if (!image_state->memory_requirements_checked) {
+                // For now just warning if sparse image binding occurs without calling to get reqs first
+                return log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                               HandleToUint64(image_state->image), kVUID_Core_MemTrack_InvalidState,
+                               "vkQueueBindSparse(): Binding sparse memory to image %s without first calling "
+                               "vkGetImageMemoryRequirements() to retrieve requirements.",
+                               device_data->report_data->FormatHandle(image_state->image).c_str());
+            }
         }
         for (uint32_t i = 0; i < bindInfo.imageOpaqueBindCount; ++i) {
-            auto image_state = GetImageState(dev_data, bindInfo.pImageOpaqueBinds[i].image);
+            const auto &image_opaque_bind = bindInfo.pImageOpaqueBinds[i];
+            auto image_state = GetImageState(bindInfo.pImageOpaqueBinds[i].image);
             if (!image_state)
                 continue;  // Param/Object validation should report image_bind.image handles being invalid, so just skip here.
             sparse_images.insert(image_state);
-            if (!image_state->get_sparse_reqs_called || image_state->sparse_requirements.empty()) {
+            if (image_state->createInfo.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) {
+                if (!image_state->get_sparse_reqs_called || image_state->sparse_requirements.empty()) {
+                    // For now just warning if sparse image binding occurs without calling to get reqs first
+                    return log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                                   HandleToUint64(image_state->image), kVUID_Core_MemTrack_InvalidState,
+                                   "vkQueueBindSparse(): Binding opaque sparse memory to image %s without first calling "
+                                   "vkGetImageSparseMemoryRequirements[2KHR]() to retrieve requirements.",
+                                   device_data->report_data->FormatHandle(image_state->image).c_str());
+                }
+            }
+            if (!image_state->memory_requirements_checked) {
                 // For now just warning if sparse image binding occurs without calling to get reqs first
-                return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                return log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                HandleToUint64(image_state->image), kVUID_Core_MemTrack_InvalidState,
-                               "vkQueueBindSparse(): Binding opaque sparse memory to image 0x%" PRIx64
-                               " without first calling vkGetImageSparseMemoryRequirements[2KHR]() to retrieve requirements.",
-                               HandleToUint64(image_state->image));
+                               "vkQueueBindSparse(): Binding opaque sparse memory to image %s without first calling "
+                               "vkGetImageMemoryRequirements() to retrieve requirements.",
+                               device_data->report_data->FormatHandle(image_state->image).c_str());
+            }
+            for (uint32_t j = 0; j < image_opaque_bind.bindCount; ++j) {
+                if (image_opaque_bind.pBinds[j].flags & VK_SPARSE_MEMORY_BIND_METADATA_BIT) {
+                    image_state->sparse_metadata_bound = true;
+                }
             }
         }
         for (const auto &sparse_image_state : sparse_images) {
             if (sparse_image_state->sparse_metadata_required && !sparse_image_state->sparse_metadata_bound) {
                 // Warn if sparse image binding metadata required for image with sparse binding, but metadata not bound
-                return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+                return log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
                                HandleToUint64(sparse_image_state->image), kVUID_Core_MemTrack_InvalidState,
-                               "vkQueueBindSparse(): Binding sparse memory to image 0x%" PRIx64
-                               " which requires a metadata aspect but no binding with VK_IMAGE_ASPECT_METADATA_BIT set was made.",
-                               HandleToUint64(sparse_image_state->image));
+                               "vkQueueBindSparse(): Binding sparse memory to image %s which requires a metadata aspect but no "
+                               "binding with VK_SPARSE_MEMORY_BIND_METADATA_BIT set was made.",
+                               device_data->report_data->FormatHandle(sparse_image_state->image).c_str());
             }
         }
     }
 
     return skip;
 }
-static void PostCallRecordQueueBindSparse(layer_data *dev_data, VkQueue queue, uint32_t bindInfoCount,
-                                          const VkBindSparseInfo *pBindInfo, VkFence fence) {
+void CoreChecks::PostCallRecordQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
+                                               VkFence fence, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (result != VK_SUCCESS) return;
     uint64_t early_retire_seq = 0;
-    auto pFence = GetFenceNode(dev_data, fence);
-    auto pQueue = GetQueueState(dev_data, queue);
+    auto pFence = GetFenceNode(fence);
+    auto pQueue = GetQueueState(queue);
 
     if (pFence) {
         if (pFence->scope == kSyncScopeInternal) {
@@ -11804,14 +11246,14 @@
         } else {
             // Retire work up until this fence early, we will not see the wait that corresponds to this signal
             early_retire_seq = pQueue->seq + pQueue->submissions.size();
-            if (!dev_data->external_sync_warning) {
-                dev_data->external_sync_warning = true;
-                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+            if (!device_data->external_sync_warning) {
+                device_data->external_sync_warning = true;
+                log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
                         HandleToUint64(fence), kVUID_Core_DrawState_QueueForwardProgress,
-                        "vkQueueBindSparse(): Signaling external fence 0x%" PRIx64 " on queue 0x%" PRIx64
-                        " will disable validation of preceding command buffer lifecycle states and the in-use status of associated "
-                        "objects.",
-                        HandleToUint64(fence), HandleToUint64(queue));
+                        "vkQueueBindSparse(): Signaling external fence %s on queue %s will disable validation of preceding command "
+                        "buffer lifecycle states and the in-use status of associated objects.",
+                        device_data->report_data->FormatHandle(fence).c_str(),
+                        device_data->report_data->FormatHandle(queue).c_str());
             }
         }
     }
@@ -11822,14 +11264,14 @@
         for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
             for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
                 auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
-                SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
+                SetSparseMemBinding(device_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
                                     HandleToUint64(bindInfo.pBufferBinds[j].buffer), kVulkanObjectTypeBuffer);
             }
         }
         for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
             for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
                 auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
-                SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
+                SetSparseMemBinding(device_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
                                     HandleToUint64(bindInfo.pImageOpaqueBinds[j].image), kVulkanObjectTypeImage);
             }
         }
@@ -11838,7 +11280,7 @@
                 auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
                 // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
                 VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
-                SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
+                SetSparseMemBinding(device_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
                                     HandleToUint64(bindInfo.pImageBinds[j].image), kVulkanObjectTypeImage);
             }
         }
@@ -11848,7 +11290,7 @@
         std::vector<VkSemaphore> semaphore_externals;
         for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
             VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 if (pSemaphore->scope == kSyncScopeInternal) {
                     if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
@@ -11868,7 +11310,7 @@
         }
         for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
             VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
-            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+            auto pSemaphore = GetSemaphoreNode(semaphore);
             if (pSemaphore) {
                 if (pSemaphore->scope == kSyncScopeInternal) {
                     pSemaphore->signaler.first = queue;
@@ -11879,14 +11321,15 @@
                 } else {
                     // Retire work up until this submit early, we will not see the wait that corresponds to this signal
                     early_retire_seq = std::max(early_retire_seq, pQueue->seq + pQueue->submissions.size() + 1);
-                    if (!dev_data->external_sync_warning) {
-                        dev_data->external_sync_warning = true;
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
-                                HandleToUint64(semaphore), kVUID_Core_DrawState_QueueForwardProgress,
-                                "vkQueueBindSparse(): Signaling external semaphore 0x%" PRIx64 " on queue 0x%" PRIx64
-                                " will disable validation of preceding command buffer lifecycle states and the in-use status of "
-                                "associated objects.",
-                                HandleToUint64(semaphore), HandleToUint64(queue));
+                    if (!device_data->external_sync_warning) {
+                        device_data->external_sync_warning = true;
+                        log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
+                                VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, HandleToUint64(semaphore),
+                                kVUID_Core_DrawState_QueueForwardProgress,
+                                "vkQueueBindSparse(): Signaling external semaphore %s on queue %s will disable validation of "
+                                "preceding command buffer lifecycle states and the in-use status of associated objects.",
+                                device_data->report_data->FormatHandle(semaphore).c_str(),
+                                device_data->report_data->FormatHandle(queue).c_str());
                     }
                 }
             }
@@ -11897,59 +11340,34 @@
     }
 
     if (early_retire_seq) {
-        RetireWorkOnQueue(dev_data, pQueue, early_retire_seq);
+        RetireWorkOnQueue(device_data, pQueue, early_retire_seq);
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
-                                               VkFence fence) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateQueueBindSparse(dev_data, queue, bindInfoCount, pBindInfo, fence);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
-
-    lock.lock();
-    PostCallRecordQueueBindSparse(dev_data, queue, bindInfoCount, pBindInfo, fence);
-    lock.unlock();
-    return result;
-}
-
-static void PostCallRecordCreateSemaphore(layer_data *dev_data, VkSemaphore *pSemaphore) {
-    SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
+void CoreChecks::PostCallRecordCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    SEMAPHORE_NODE *sNode = &device_data->semaphoreMap[*pSemaphore];
     sNode->signaler.first = VK_NULL_HANDLE;
     sNode->signaler.second = 0;
     sNode->signaled = false;
     sNode->scope = kSyncScopeInternal;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
-                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
-    if (result == VK_SUCCESS) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateSemaphore(dev_data, pSemaphore);
-    }
-    return result;
-}
-
-static bool PreCallValidateImportSemaphore(layer_data *dev_data, VkSemaphore semaphore, const char *caller_name) {
-    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(dev_data, semaphore);
-    VK_OBJECT obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
+bool CoreChecks::ValidateImportSemaphore(layer_data *device_data, VkSemaphore semaphore, const char *caller_name) {
     bool skip = false;
+    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(semaphore);
     if (sema_node) {
-        skip |= ValidateObjectNotInUse(dev_data, sema_node, obj_struct, caller_name, kVUIDUndefined);
+        VK_OBJECT obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
+        skip |= ValidateObjectNotInUse(device_data, sema_node, obj_struct, caller_name, kVUIDUndefined);
     }
     return skip;
 }
 
-static void PostCallRecordImportSemaphore(layer_data *dev_data, VkSemaphore semaphore,
-                                          VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type, VkSemaphoreImportFlagsKHR flags) {
-    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(dev_data, semaphore);
+void CoreChecks::RecordImportSemaphoreState(layer_data *device_data, VkSemaphore semaphore,
+                                            VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type, VkSemaphoreImportFlagsKHR flags) {
+    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(semaphore);
     if (sema_node && sema_node->scope != kSyncScopeExternalPermanent) {
         if ((handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR || flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) &&
             sema_node->scope == kSyncScopeInternal) {
@@ -11961,88 +11379,74 @@
 }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-VKAPI_ATTR VkResult VKAPI_CALL
-ImportSemaphoreWin32HandleKHR(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip =
-        PreCallValidateImportSemaphore(dev_data, pImportSemaphoreWin32HandleInfo->semaphore, "vkImportSemaphoreWin32HandleKHR");
-
-    if (!skip) {
-        result = dev_data->dispatch_table.ImportSemaphoreWin32HandleKHR(device, pImportSemaphoreWin32HandleInfo);
-    }
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordImportSemaphore(dev_data, pImportSemaphoreWin32HandleInfo->semaphore,
-                                      pImportSemaphoreWin32HandleInfo->handleType, pImportSemaphoreWin32HandleInfo->flags);
-    }
-    return result;
-}
-#endif
-
-VKAPI_ATTR VkResult VKAPI_CALL ImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = PreCallValidateImportSemaphore(dev_data, pImportSemaphoreFdInfo->semaphore, "vkImportSemaphoreFdKHR");
-
-    if (!skip) {
-        result = dev_data->dispatch_table.ImportSemaphoreFdKHR(device, pImportSemaphoreFdInfo);
-    }
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordImportSemaphore(dev_data, pImportSemaphoreFdInfo->semaphore, pImportSemaphoreFdInfo->handleType,
-                                      pImportSemaphoreFdInfo->flags);
-    }
-    return result;
+bool CoreChecks::PreCallValidateImportSemaphoreWin32HandleKHR(
+    VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateImportSemaphore(device_data, pImportSemaphoreWin32HandleInfo->semaphore, "vkImportSemaphoreWin32HandleKHR");
 }
 
-static void PostCallRecordGetSemaphore(layer_data *dev_data, VkSemaphore semaphore,
-                                       VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type) {
-    SEMAPHORE_NODE *sema_node = GetSemaphoreNode(dev_data, semaphore);
-    if (sema_node && handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
+void CoreChecks::PostCallRecordImportSemaphoreWin32HandleKHR(
+    VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordImportSemaphoreState(device_data, pImportSemaphoreWin32HandleInfo->semaphore, pImportSemaphoreWin32HandleInfo->handleType,
+                               pImportSemaphoreWin32HandleInfo->flags);
+}
+#endif  // VK_USE_PLATFORM_WIN32_KHR
+
+bool CoreChecks::PreCallValidateImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateImportSemaphore(device_data, pImportSemaphoreFdInfo->semaphore, "vkImportSemaphoreFdKHR");
+}
+
+void CoreChecks::PostCallRecordImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo,
+                                                    VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordImportSemaphoreState(device_data, pImportSemaphoreFdInfo->semaphore, pImportSemaphoreFdInfo->handleType,
+                               pImportSemaphoreFdInfo->flags);
+}
+
+void CoreChecks::RecordGetExternalSemaphoreState(layer_data *device_data, VkSemaphore semaphore,
+                                                 VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type) {
+    SEMAPHORE_NODE *semaphore_state = GetSemaphoreNode(semaphore);
+    if (semaphore_state && handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
         // Cannot track semaphore state once it is exported, except for Sync FD handle types which have copy transference
-        sema_node->scope = kSyncScopeExternalPermanent;
+        semaphore_state->scope = kSyncScopeExternalPermanent;
     }
 }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-VKAPI_ATTR VkResult VKAPI_CALL GetSemaphoreWin32HandleKHR(VkDevice device,
+void CoreChecks::PostCallRecordGetSemaphoreWin32HandleKHR(VkDevice device,
                                                           const VkSemaphoreGetWin32HandleInfoKHR *pGetWin32HandleInfo,
-                                                          HANDLE *pHandle) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.GetSemaphoreWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetSemaphore(dev_data, pGetWin32HandleInfo->semaphore, pGetWin32HandleInfo->handleType);
-    }
-    return result;
+                                                          HANDLE *pHandle, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordGetExternalSemaphoreState(device_data, pGetWin32HandleInfo->semaphore, pGetWin32HandleInfo->handleType);
 }
 #endif
 
-VKAPI_ATTR VkResult VKAPI_CALL GetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR *pGetFdInfo, int *pFd) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.GetSemaphoreFdKHR(device, pGetFdInfo, pFd);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetSemaphore(dev_data, pGetFdInfo->semaphore, pGetFdInfo->handleType);
-    }
-    return result;
+void CoreChecks::PostCallRecordGetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR *pGetFdInfo, int *pFd,
+                                                 VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordGetExternalSemaphoreState(device_data, pGetFdInfo->semaphore, pGetFdInfo->handleType);
 }
 
-static bool PreCallValidateImportFence(layer_data *dev_data, VkFence fence, const char *caller_name) {
-    FENCE_NODE *fence_node = GetFenceNode(dev_data, fence);
+bool CoreChecks::ValidateImportFence(layer_data *device_data, VkFence fence, const char *caller_name) {
+    FENCE_NODE *fence_node = GetFenceNode(fence);
     bool skip = false;
     if (fence_node && fence_node->scope == kSyncScopeInternal && fence_node->state == FENCE_INFLIGHT) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
-                        HandleToUint64(fence), kVUIDUndefined, "Cannot call %s on fence 0x%" PRIx64 " that is currently in use.",
-                        caller_name, HandleToUint64(fence));
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
+                        HandleToUint64(fence), kVUIDUndefined, "Cannot call %s on fence %s that is currently in use.", caller_name,
+                        device_data->report_data->FormatHandle(fence).c_str());
     }
     return skip;
 }
 
-static void PostCallRecordImportFence(layer_data *dev_data, VkFence fence, VkExternalFenceHandleTypeFlagBitsKHR handle_type,
-                                      VkFenceImportFlagsKHR flags) {
-    FENCE_NODE *fence_node = GetFenceNode(dev_data, fence);
+void CoreChecks::RecordImportFenceState(layer_data *device_data, VkFence fence, VkExternalFenceHandleTypeFlagBitsKHR handle_type,
+                                        VkFenceImportFlagsKHR flags) {
+    FENCE_NODE *fence_node = GetFenceNode(fence);
     if (fence_node && fence_node->scope != kSyncScopeExternalPermanent) {
         if ((handle_type == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR || flags & VK_FENCE_IMPORT_TEMPORARY_BIT_KHR) &&
             fence_node->scope == kSyncScopeInternal) {
@@ -12054,113 +11458,88 @@
 }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-VKAPI_ATTR VkResult VKAPI_CALL ImportFenceWin32HandleKHR(VkDevice device,
-                                                         const VkImportFenceWin32HandleInfoKHR *pImportFenceWin32HandleInfo) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = PreCallValidateImportFence(dev_data, pImportFenceWin32HandleInfo->fence, "vkImportFenceWin32HandleKHR");
-
-    if (!skip) {
-        result = dev_data->dispatch_table.ImportFenceWin32HandleKHR(device, pImportFenceWin32HandleInfo);
-    }
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordImportFence(dev_data, pImportFenceWin32HandleInfo->fence, pImportFenceWin32HandleInfo->handleType,
-                                  pImportFenceWin32HandleInfo->flags);
-    }
-    return result;
+bool CoreChecks::PreCallValidateImportFenceWin32HandleKHR(VkDevice device,
+                                                          const VkImportFenceWin32HandleInfoKHR *pImportFenceWin32HandleInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateImportFence(device_data, pImportFenceWin32HandleInfo->fence, "vkImportFenceWin32HandleKHR");
 }
-#endif
+void CoreChecks::PostCallRecordImportFenceWin32HandleKHR(VkDevice device,
+                                                         const VkImportFenceWin32HandleInfoKHR *pImportFenceWin32HandleInfo,
+                                                         VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordImportFenceState(device_data, pImportFenceWin32HandleInfo->fence, pImportFenceWin32HandleInfo->handleType,
+                           pImportFenceWin32HandleInfo->flags);
+}
+#endif  // VK_USE_PLATFORM_WIN32_KHR
 
-VKAPI_ATTR VkResult VKAPI_CALL ImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = PreCallValidateImportFence(dev_data, pImportFenceFdInfo->fence, "vkImportFenceFdKHR");
-
-    if (!skip) {
-        result = dev_data->dispatch_table.ImportFenceFdKHR(device, pImportFenceFdInfo);
-    }
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordImportFence(dev_data, pImportFenceFdInfo->fence, pImportFenceFdInfo->handleType, pImportFenceFdInfo->flags);
-    }
-    return result;
+bool CoreChecks::PreCallValidateImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateImportFence(device_data, pImportFenceFdInfo->fence, "vkImportFenceFdKHR");
+}
+void CoreChecks::PostCallRecordImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo,
+                                                VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordImportFenceState(device_data, pImportFenceFdInfo->fence, pImportFenceFdInfo->handleType, pImportFenceFdInfo->flags);
 }
 
-static void PostCallRecordGetFence(layer_data *dev_data, VkFence fence, VkExternalFenceHandleTypeFlagBitsKHR handle_type) {
-    FENCE_NODE *fence_node = GetFenceNode(dev_data, fence);
-    if (fence_node) {
+void CoreChecks::RecordGetExternalFenceState(layer_data *device_data, VkFence fence,
+                                             VkExternalFenceHandleTypeFlagBitsKHR handle_type) {
+    FENCE_NODE *fence_state = GetFenceNode(fence);
+    if (fence_state) {
         if (handle_type != VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
             // Export with reference transference becomes external
-            fence_node->scope = kSyncScopeExternalPermanent;
-        } else if (fence_node->scope == kSyncScopeInternal) {
+            fence_state->scope = kSyncScopeExternalPermanent;
+        } else if (fence_state->scope == kSyncScopeInternal) {
             // Export with copy transference has a side effect of resetting the fence
-            fence_node->state = FENCE_UNSIGNALED;
+            fence_state->state = FENCE_UNSIGNALED;
         }
     }
 }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-VKAPI_ATTR VkResult VKAPI_CALL GetFenceWin32HandleKHR(VkDevice device, const VkFenceGetWin32HandleInfoKHR *pGetWin32HandleInfo,
-                                                      HANDLE *pHandle) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.GetFenceWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetFence(dev_data, pGetWin32HandleInfo->fence, pGetWin32HandleInfo->handleType);
-    }
-    return result;
+void CoreChecks::PostCallRecordGetFenceWin32HandleKHR(VkDevice device, const VkFenceGetWin32HandleInfoKHR *pGetWin32HandleInfo,
+                                                      HANDLE *pHandle, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordGetExternalFenceState(device_data, pGetWin32HandleInfo->fence, pGetWin32HandleInfo->handleType);
 }
 #endif
 
-VKAPI_ATTR VkResult VKAPI_CALL GetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR *pGetFdInfo, int *pFd) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.GetFenceFdKHR(device, pGetFdInfo, pFd);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetFence(dev_data, pGetFdInfo->fence, pGetFdInfo->handleType);
-    }
-    return result;
+void CoreChecks::PostCallRecordGetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR *pGetFdInfo, int *pFd, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordGetExternalFenceState(device_data, pGetFdInfo->fence, pGetFdInfo->handleType);
 }
 
-static void PostCallRecordCreateEvent(layer_data *dev_data, VkEvent *pEvent) {
-    dev_data->eventMap[*pEvent].needsSignaled = false;
-    dev_data->eventMap[*pEvent].write_in_use = 0;
-    dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
+void CoreChecks::PostCallRecordCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    device_data->eventMap[*pEvent].needsSignaled = false;
+    device_data->eventMap[*pEvent].write_in_use = 0;
+    device_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
-                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
-    if (result == VK_SUCCESS) {
-        lock_guard_t lock(global_lock);
-        PostCallRecordCreateEvent(dev_data, pEvent);
-    }
-    return result;
-}
+bool CoreChecks::ValidateCreateSwapchain(layer_data *device_data, const char *func_name,
+                                         VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
+                                         SWAPCHAIN_NODE *old_swapchain_state) {
+    VkDevice device = device_data->device;
 
-static bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
-                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
-                                              SWAPCHAIN_NODE *old_swapchain_state) {
-    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
-
-    // TODO: revisit this. some of these rules are being relaxed.
-
-    // All physical devices and queue families are required to be able
-    // to present to any native window on Android; require the
+    // All physical devices and queue families are required to be able to present to any native window on Android; require the
     // application to have established support on any other platform.
-    if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
-        auto support_predicate = [dev_data](decltype(surface_state->gpu_queue_support)::value_type qs) -> bool {
+    if (!device_data->instance_extensions.vk_khr_android_surface) {
+        auto support_predicate = [device_data](decltype(surface_state->gpu_queue_support)::value_type qs) -> bool {
             // TODO: should restrict search only to queue families of VkDeviceQueueCreateInfos, not whole phys. device
-            return (qs.first.gpu == dev_data->physical_device) && qs.second;
+            return (qs.first.gpu == device_data->physical_device) && qs.second;
         };
         const auto &support = surface_state->gpu_queue_support;
         bool is_supported = std::any_of(support.begin(), support.end(), support_predicate);
 
         if (!is_supported) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-surface-01270",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-surface-01270",
                         "%s: pCreateInfo->surface is not known at this time to be supported for presentation by this device. The "
                         "vkGetPhysicalDeviceSurfaceSupportKHR() must be called beforehand, and it must return VK_TRUE support with "
                         "this surface for at least one queue family of this device.",
@@ -12169,39 +11548,41 @@
         }
     }
 
-    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
-        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                    HandleToUint64(dev_data->device), kVUID_Core_DrawState_SwapchainAlreadyExists,
-                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
-            return true;
-    }
-    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
-        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                    HandleToUint64(pCreateInfo->oldSwapchain), kVUID_Core_DrawState_SwapchainWrongSurface,
-                    "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
-            return true;
+    if (old_swapchain_state) {
+        if (old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                        HandleToUint64(pCreateInfo->oldSwapchain), "VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933",
+                        "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
+                return true;
+        }
+        if (old_swapchain_state->retired) {
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                        HandleToUint64(pCreateInfo->oldSwapchain), "VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933",
+                        "%s: pCreateInfo->oldSwapchain is retired", func_name))
+                return true;
+        }
     }
 
     if ((pCreateInfo->imageExtent.width == 0) || (pCreateInfo->imageExtent.height == 0)) {
-        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                    HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageExtent-01689",
+        if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageExtent-01689",
                     "%s: pCreateInfo->imageExtent = (%d, %d) which is illegal.", func_name, pCreateInfo->imageExtent.width,
                     pCreateInfo->imageExtent.height))
             return true;
     }
 
-    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
+    auto physical_device_state = GetPhysicalDeviceState();
     if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
-        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
-                    HandleToUint64(dev_data->physical_device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
+        if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                    HandleToUint64(device_data->physical_device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
                     "%s: surface capabilities not retrieved for this physical device", func_name))
             return true;
     } else {  // have valid capabilities
         auto &capabilities = physical_device_state->surfaceCapabilities;
         // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
         if (pCreateInfo->minImageCount < capabilities.minImageCount) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01271",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01271",
                         "%s called with minImageCount = %d, which is outside the bounds returned by "
                         "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d).",
                         func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount))
@@ -12209,8 +11590,8 @@
         }
 
         if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01272",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01272",
                         "%s called with minImageCount = %d, which is outside the bounds returned by "
                         "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d).",
                         func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount))
@@ -12222,8 +11603,8 @@
             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height)) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageExtent-01274",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageExtent-01274",
                         "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
                         "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
                         "maxImageExtent = (%d,%d).",
@@ -12253,9 +11634,8 @@
                 }
             }
             // Log the message that we've built up:
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-preTransform-01279", "%s.",
-                        errorString.c_str()))
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-preTransform-01279", "%s.", errorString.c_str()))
                 return true;
         }
 
@@ -12280,23 +11660,22 @@
                 }
             }
             // Log the message that we've built up:
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280", "%s.",
-                        errorString.c_str()))
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280", "%s.", errorString.c_str()))
                 return true;
         }
         // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
         if (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275",
                         "%s called with a non-supported imageArrayLayers (i.e. %d).  Maximum value is %d.", func_name,
                         pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers))
                 return true;
         }
         // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
         if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageUsage-01276",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageUsage-01276",
                         "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x.",
                         func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags))
                 return true;
@@ -12305,8 +11684,8 @@
 
     // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
     if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
-        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                    HandleToUint64(dev_data->device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
+        if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                    HandleToUint64(device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
                     "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
             return true;
     } else {
@@ -12330,15 +11709,15 @@
         }
         if (!foundMatch) {
             if (!foundFormat) {
-                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                            HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
+                if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
                             "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d).", func_name,
                             pCreateInfo->imageFormat))
                     return true;
             }
             if (!foundColorSpace) {
-                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                            HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
+                if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
                             "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d).", func_name,
                             pCreateInfo->imageColorSpace))
                     return true;
@@ -12350,8 +11729,8 @@
     if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
         // FIFO is required to always be supported
         if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), kVUID_Core_DrawState_SwapchainCreateBeforeQuery,
                         "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
                 return true;
         }
@@ -12360,8 +11739,8 @@
         bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
                                     pCreateInfo->presentMode) != physical_device_state->present_modes.end();
         if (!foundMatch) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-presentMode-01281",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-presentMode-01281",
                         "%s called with a non-supported presentMode (i.e. %s).", func_name,
                         string_VkPresentModeKHR(pCreateInfo->presentMode)))
                 return true;
@@ -12370,16 +11749,16 @@
     // Validate state for shared presentable case
     if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
         VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
-        if (!dev_data->extensions.vk_khr_shared_presentable_image) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), kVUID_Core_DrawState_ExtensionNotEnabled,
+        if (!device_data->device_extensions.vk_khr_shared_presentable_image) {
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), kVUID_Core_DrawState_ExtensionNotEnabled,
                         "%s called with presentMode %s which requires the VK_KHR_shared_presentable_image extension, which has not "
                         "been enabled.",
                         func_name, string_VkPresentModeKHR(pCreateInfo->presentMode)))
                 return true;
         } else if (pCreateInfo->minImageCount != 1) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(dev_data->device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01383",
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-minImageCount-01383",
                         "%s called with presentMode %s, but minImageCount value is %d. For shared presentable image, minImageCount "
                         "must be 1.",
                         func_name, string_VkPresentModeKHR(pCreateInfo->presentMode), pCreateInfo->minImageCount))
@@ -12387,94 +11766,139 @@
         }
     }
 
+    if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+        if (!device_data->device_extensions.vk_khr_swapchain_mutable_format) {
+            if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                        HandleToUint64(device), kVUID_Core_DrawState_ExtensionNotEnabled,
+                        "%s: pCreateInfo->flags contains VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR which requires the "
+                        "VK_KHR_swapchain_mutable_format extension, which has not been enabled.",
+                        func_name))
+                return true;
+        } else {
+            const auto *image_format_list = lvl_find_in_chain<VkImageFormatListCreateInfoKHR>(pCreateInfo->pNext);
+            if (image_format_list == nullptr) {
+                if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-flags-03168",
+                            "%s: pCreateInfo->flags contains VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR but the pNext chain of "
+                            "pCreateInfo does not contain an instance of VkImageFormatListCreateInfoKHR.",
+                            func_name))
+                    return true;
+            } else if (image_format_list->viewFormatCount == 0) {
+                if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                            HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-flags-03168",
+                            "%s: pCreateInfo->flags contains VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR but the viewFormatCount "
+                            "member of VkImageFormatListCreateInfoKHR in the pNext chain is zero.",
+                            func_name))
+                    return true;
+            } else {
+                bool found_base_format = false;
+                for (uint32_t i = 0; i < image_format_list->viewFormatCount; ++i) {
+                    if (image_format_list->pViewFormats[i] == pCreateInfo->imageFormat) {
+                        found_base_format = true;
+                        break;
+                    }
+                }
+                if (!found_base_format) {
+                    if (log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+                                HandleToUint64(device), "VUID-VkSwapchainCreateInfoKHR-flags-03168",
+                                "%s: pCreateInfo->flags contains VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR but none of the "
+                                "elements of the pViewFormats member of VkImageFormatListCreateInfoKHR match "
+                                "pCreateInfo->imageFormat.",
+                                func_name))
+                        return true;
+                }
+            }
+        }
+    }
+
+    if ((pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) && pCreateInfo->pQueueFamilyIndices) {
+        bool skip = ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
+                                          "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices",
+                                          "VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428",
+                                          "VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428", false);
+        if (skip) return true;
+    }
+
     return false;
 }
 
-static void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
-                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
-                                             SWAPCHAIN_NODE *old_swapchain_state) {
+bool CoreChecks::PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto surface_state = GetSurfaceState(pCreateInfo->surface);
+    auto old_swapchain_state = GetSwapchainNode(pCreateInfo->oldSwapchain);
+    return ValidateCreateSwapchain(device_data, "vkCreateSwapchainKHR()", pCreateInfo, surface_state, old_swapchain_state);
+}
+
+static void RecordCreateSwapchainState(layer_data *device_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                       VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
+                                       SWAPCHAIN_NODE *old_swapchain_state) {
     if (VK_SUCCESS == result) {
-        lock_guard_t lock(global_lock);
         auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
         if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
             VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
             swapchain_state->shared_presentable = true;
         }
         surface_state->swapchain = swapchain_state.get();
-        dev_data->swapchainMap[*pSwapchain] = std::move(swapchain_state);
+        device_data->swapchainMap[*pSwapchain] = std::move(swapchain_state);
     } else {
         surface_state->swapchain = nullptr;
     }
-    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
+    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain is retired
     if (old_swapchain_state) {
-        old_swapchain_state->replaced = true;
+        old_swapchain_state->retired = true;
     }
-    surface_state->old_swapchain = old_swapchain_state;
     return;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
-                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
-    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
-
-    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-
-    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
-
-    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
-
-    return result;
+void CoreChecks::PostCallRecordCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain,
+                                                  VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto surface_state = GetSurfaceState(pCreateInfo->surface);
+    auto old_swapchain_state = GetSwapchainNode(pCreateInfo->oldSwapchain);
+    RecordCreateSwapchainState(device_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
 }
 
-static void PreCallRecordDestroySwapchainKHR(layer_data *dev_data, const VkSwapchainKHR swapchain) {
-    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
+void CoreChecks::PreCallRecordDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
+                                                  const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!swapchain) return;
+    auto swapchain_data = GetSwapchainNode(swapchain);
     if (swapchain_data) {
         if (swapchain_data->images.size() > 0) {
             for (auto swapchain_image : swapchain_data->images) {
-                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
-                if (image_sub != dev_data->imageSubresourceMap.end()) {
+                auto image_sub = device_data->imageSubresourceMap.find(swapchain_image);
+                if (image_sub != device_data->imageSubresourceMap.end()) {
                     for (auto imgsubpair : image_sub->second) {
-                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
-                        if (image_item != dev_data->imageLayoutMap.end()) {
-                            dev_data->imageLayoutMap.erase(image_item);
+                        auto image_item = device_data->imageLayoutMap.find(imgsubpair);
+                        if (image_item != device_data->imageLayoutMap.end()) {
+                            device_data->imageLayoutMap.erase(image_item);
                         }
                     }
-                    dev_data->imageSubresourceMap.erase(image_sub);
+                    device_data->imageSubresourceMap.erase(image_sub);
                 }
-                ClearMemoryObjectBindings(dev_data, HandleToUint64(swapchain_image), kVulkanObjectTypeSwapchainKHR);
-                EraseQFOImageRelaseBarriers(dev_data, swapchain_image);
-                dev_data->imageMap.erase(swapchain_image);
+                ClearMemoryObjectBindings(HandleToUint64(swapchain_image), kVulkanObjectTypeSwapchainKHR);
+                EraseQFOImageRelaseBarriers(device_data, swapchain_image);
+                device_data->imageMap.erase(swapchain_image);
             }
         }
 
-        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
+        auto surface_state = GetSurfaceState(swapchain_data->createInfo.surface);
         if (surface_state) {
             if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
-            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
         }
 
-        dev_data->swapchainMap.erase(swapchain);
+        device_data->swapchainMap.erase(swapchain);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordDestroySwapchainKHR(dev_data, swapchain);
-    lock.unlock();
-    dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
-}
-
-static bool PreCallValidateGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
-                                                 uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
+bool CoreChecks::PreCallValidateGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                      VkImage *pSwapchainImages) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto swapchain_state = GetSwapchainNode(swapchain);
     bool skip = false;
     if (swapchain_state && pSwapchainImages) {
-        lock_guard_t lock(global_lock);
         // Compare the preliminary value of *pSwapchainImageCount with the value this time:
         if (swapchain_state->vkGetSwapchainImagesKHRState == UNCALLED) {
             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
@@ -12493,9 +11917,12 @@
     return skip;
 }
 
-static void PostCallRecordGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
-                                                uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
-    lock_guard_t lock(global_lock);
+void CoreChecks::PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                     VkImage *pSwapchainImages, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    auto swapchain_state = GetSwapchainNode(swapchain);
 
     if (*pSwapchainImageCount > swapchain_state->images.size()) swapchain_state->images.resize(*pSwapchainImageCount);
 
@@ -12542,52 +11969,34 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
-                                                     VkImage *pSwapchainImages) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    auto swapchain_state = GetSwapchainNode(device_data, swapchain);
-    bool skip = PreCallValidateGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
-
-    if (!skip) {
-        result = device_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
-    }
-
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE)) {
-        PostCallRecordGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
-    }
-    return result;
-}
-
-static bool PreCallValidateQueuePresentKHR(layer_data *dev_data, VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
+bool CoreChecks::PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
     bool skip = false;
-
-    lock_guard_t lock(global_lock);
-    auto queue_state = GetQueueState(dev_data, queue);
+    auto queue_state = GetQueueState(queue);
 
     for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
-        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
+        auto pSemaphore = GetSemaphoreNode(pPresentInfo->pWaitSemaphores[i]);
         if (pSemaphore && !pSemaphore->signaled) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
-                            kVUID_Core_DrawState_QueueForwardProgress,
-                            "Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
-                            HandleToUint64(queue), HandleToUint64(pPresentInfo->pWaitSemaphores[i]));
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            0, kVUID_Core_DrawState_QueueForwardProgress,
+                            "Queue %s is waiting on semaphore %s that has no way to be signaled.",
+                            device_data->report_data->FormatHandle(queue).c_str(),
+                            device_data->report_data->FormatHandle(pPresentInfo->pWaitSemaphores[i]).c_str());
         }
     }
 
     for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
-        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
+        auto swapchain_data = GetSwapchainNode(pPresentInfo->pSwapchains[i]);
         if (swapchain_data) {
             if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
                 skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                             HandleToUint64(pPresentInfo->pSwapchains[i]), kVUID_Core_DrawState_SwapchainInvalidImage,
                             "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
                             pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
             } else {
                 auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
-                auto image_state = GetImageState(dev_data, image);
+                auto image_state = GetImageState(image);
 
                 if (image_state->shared_presentable) {
                     image_state->layout_locked = true;
@@ -12595,22 +12004,23 @@
 
                 if (!image_state->acquired) {
                     skip |= log_msg(
-                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                         HandleToUint64(pPresentInfo->pSwapchains[i]), kVUID_Core_DrawState_SwapchainImageNotAcquired,
                         "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
                 }
 
                 vector<VkImageLayout> layouts;
-                if (FindLayouts(dev_data, image, layouts)) {
+                if (FindLayouts(device_data, image, layouts)) {
                     for (auto layout : layouts) {
-                        if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) && (!dev_data->extensions.vk_khr_shared_presentable_image ||
-                                                                            (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
-                            skip |=
-                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
-                                        HandleToUint64(queue), "VUID-VkPresentInfoKHR-pImageIndices-01296",
-                                        "Images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or "
-                                        "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s.",
-                                        string_VkImageLayout(layout));
+                        if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) &&
+                            (!device_data->device_extensions.vk_khr_shared_presentable_image ||
+                             (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
+                            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                            VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, HandleToUint64(queue),
+                                            "VUID-VkPresentInfoKHR-pImageIndices-01296",
+                                            "Images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or "
+                                            "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s.",
+                                            string_VkImageLayout(layout));
                         }
                     }
                 }
@@ -12618,20 +12028,21 @@
 
             // All physical devices and queue families are required to be able to present to any native window on Android; require
             // the application to have established support on any other platform.
-            if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
-                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
-                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
+            if (!device_data->instance_extensions.vk_khr_android_surface) {
+                auto surface_state = GetSurfaceState(swapchain_data->createInfo.surface);
+                auto support_it =
+                    surface_state->gpu_queue_support.find({device_data->physical_device, queue_state->queueFamilyIndex});
 
                 if (support_it == surface_state->gpu_queue_support.end()) {
-                    skip |=
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                                HandleToUint64(pPresentInfo->pSwapchains[i]), kVUID_Core_DrawState_SwapchainUnsupportedQueue,
-                                "vkQueuePresentKHR: Presenting image without calling vkGetPhysicalDeviceSurfaceSupportKHR");
+                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
+                                    kVUID_Core_DrawState_SwapchainUnsupportedQueue,
+                                    "vkQueuePresentKHR: Presenting image without calling vkGetPhysicalDeviceSurfaceSupportKHR");
                 } else if (!support_it->second) {
-                    skip |=
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                                HandleToUint64(pPresentInfo->pSwapchains[i]), "VUID-vkQueuePresentKHR-pSwapchains-01292",
-                                "vkQueuePresentKHR: Presenting image on queue that cannot present to this surface.");
+                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
+                                    "VUID-vkQueuePresentKHR-pSwapchains-01292",
+                                    "vkQueuePresentKHR: Presenting image on queue that cannot present to this surface.");
                 }
             }
         }
@@ -12641,13 +12052,13 @@
         const auto *present_regions = lvl_find_in_chain<VkPresentRegionsKHR>(pPresentInfo->pNext);
         if (present_regions) {
             for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
-                auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
+                auto swapchain_data = GetSwapchainNode(pPresentInfo->pSwapchains[i]);
                 assert(swapchain_data);
                 VkPresentRegionKHR region = present_regions->pRegions[i];
                 for (uint32_t j = 0; j < region.rectangleCount; ++j) {
                     VkRectLayerKHR rect = region.pRectangles[j];
                     if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
-                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                         VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
                                         "VUID-VkRectLayerKHR-offset-01261",
                                         "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, "
@@ -12656,7 +12067,7 @@
                                         i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
                     }
                     if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
-                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                         VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
                                         "VUID-VkRectLayerKHR-offset-01261",
                                         "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, "
@@ -12666,7 +12077,7 @@
                     }
                     if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
                         skip |= log_msg(
-                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                            device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                             HandleToUint64(pPresentInfo->pSwapchains[i]), "VUID-VkRectLayerKHR-layer-01262",
                             "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the layer "
                             "(%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
@@ -12680,7 +12091,7 @@
         if (present_times_info) {
             if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
                 skip |=
-                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                    log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                             HandleToUint64(pPresentInfo->pSwapchains[0]), "VUID-VkPresentTimesInfoGOOGLE-swapchainCount-01247",
                             "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but pPresentInfo->swapchainCount "
                             "is %i. For VkPresentTimesInfoGOOGLE down pNext chain of VkPresentInfoKHR, "
@@ -12693,10 +12104,10 @@
     return skip;
 }
 
-static void PostCallRecordQueuePresentKHR(layer_data *dev_data, const VkPresentInfoKHR *pPresentInfo, const VkResult &result) {
+void CoreChecks::PostCallRecordQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo, VkResult result) {
     // Semaphore waits occur before error generation, if the call reached the ICD. (Confirm?)
     for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
-        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
+        auto pSemaphore = GetSemaphoreNode(pPresentInfo->pWaitSemaphores[i]);
         if (pSemaphore) {
             pSemaphore->signaler.first = VK_NULL_HANDLE;
             pSemaphore->signaled = false;
@@ -12707,148 +12118,91 @@
         // Note: this is imperfect, in that we can get confused about what did or didn't succeed-- but if the app does that, it's
         // confused itself just as much.
         auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
-
         if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
-
         // Mark the image as having been released to the WSI
-        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
+        auto swapchain_data = GetSwapchainNode(pPresentInfo->pSwapchains[i]);
         if (swapchain_data && (swapchain_data->images.size() > pPresentInfo->pImageIndices[i])) {
             auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
-            auto image_state = GetImageState(dev_data, image);
+            auto image_state = GetImageState(image);
             if (image_state) {
                 image_state->acquired = false;
             }
         }
     }
-
     // Note: even though presentation is directed to a queue, there is no direct ordering between QP and subsequent work, so QP (and
     // its semaphore waits) /never/ participate in any completion proof.
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-
-    bool skip = PreCallValidateQueuePresentKHR(dev_data, queue, pPresentInfo);
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
-
-    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
-        PostCallRecordQueuePresentKHR(dev_data, pPresentInfo, result);
-    }
-
-    return result;
-}
-
-static bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
-                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
-                                                     std::vector<SURFACE_STATE *> &surface_state,
-                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
+bool CoreChecks::PreCallValidateCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
+                                                          const VkSwapchainCreateInfoKHR *pCreateInfos,
+                                                          const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
     if (pCreateInfos) {
-        lock_guard_t lock(global_lock);
         for (uint32_t i = 0; i < swapchainCount; i++) {
-            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
-            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
+            auto surface_state = GetSurfaceState(pCreateInfos[i].surface);
+            auto old_swapchain_state = GetSwapchainNode(pCreateInfos[i].oldSwapchain);
             std::stringstream func_name;
-            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
-            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
-                                                  old_swapchain_state[i])) {
-                return true;
-            }
+            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]()";
+            skip |=
+                ValidateCreateSwapchain(device_data, func_name.str().c_str(), &pCreateInfos[i], surface_state, old_swapchain_state);
         }
     }
-    return false;
+    return skip;
 }
 
-static void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
-                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
-                                                    std::vector<SURFACE_STATE *> &surface_state,
-                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
-    if (VK_SUCCESS == result) {
-        for (uint32_t i = 0; i < swapchainCount; i++) {
-            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
-            if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfos[i].presentMode ||
-                VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfos[i].presentMode) {
-                swapchain_state->shared_presentable = true;
-            }
-            surface_state[i]->swapchain = swapchain_state.get();
-            dev_data->swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
-        }
-    } else {
-        for (uint32_t i = 0; i < swapchainCount; i++) {
-            surface_state[i]->swapchain = nullptr;
-        }
-    }
-    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
-    for (uint32_t i = 0; i < swapchainCount; i++) {
-        if (old_swapchain_state[i]) {
-            old_swapchain_state[i]->replaced = true;
-        }
-        surface_state[i]->old_swapchain = old_swapchain_state[i];
-    }
-    return;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
+void CoreChecks::PostCallRecordCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
                                                          const VkSwapchainCreateInfoKHR *pCreateInfos,
-                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::vector<SURFACE_STATE *> surface_state;
-    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
-
-    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
-                                                 old_swapchain_state)) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
+                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains,
+                                                         VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (pCreateInfos) {
+        for (uint32_t i = 0; i < swapchainCount; i++) {
+            auto surface_state = GetSurfaceState(pCreateInfos[i].surface);
+            auto old_swapchain_state = GetSwapchainNode(pCreateInfos[i].oldSwapchain);
+            RecordCreateSwapchainState(device_data, result, &pCreateInfos[i], &pSwapchains[i], surface_state, old_swapchain_state);
+        }
     }
-
-    VkResult result =
-        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
-
-    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
-                                            old_swapchain_state);
-
-    return result;
 }
 
-static bool PreCallValidateCommonAcquireNextImage(layer_data *dev_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
-                                                  VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex,
-                                                  const char *func_name) {
+bool CoreChecks::ValidateAcquireNextImage(layer_data *device_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                          VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex, const char *func_name) {
     bool skip = false;
     if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
                         HandleToUint64(device), "VUID-vkAcquireNextImageKHR-semaphore-01780",
                         "%s: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way to "
                         "determine the completion of this operation.",
                         func_name);
     }
 
-    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+    auto pSemaphore = GetSemaphoreNode(semaphore);
     if (pSemaphore && pSemaphore->scope == kSyncScopeInternal && pSemaphore->signaled) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
                         HandleToUint64(semaphore), "VUID-vkAcquireNextImageKHR-semaphore-01286",
                         "%s: Semaphore must not be currently signaled or in a wait state.", func_name);
     }
 
-    auto pFence = GetFenceNode(dev_data, fence);
+    auto pFence = GetFenceNode(fence);
     if (pFence) {
-        skip |= ValidateFenceForSubmit(dev_data, pFence);
+        skip |= ValidateFenceForSubmit(device_data, pFence);
     }
 
-    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
-    if (swapchain_data && swapchain_data->replaced) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+    auto swapchain_data = GetSwapchainNode(swapchain);
+    if (swapchain_data && swapchain_data->retired) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                         HandleToUint64(swapchain), "VUID-vkAcquireNextImageKHR-swapchain-01285",
                         "%s: This swapchain has been retired. The application can still present any images it "
                         "has acquired, but cannot acquire any more.",
                         func_name);
     }
 
-    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
+    auto physical_device_state = GetPhysicalDeviceState();
     if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
         uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
-                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
+                                                 [=](VkImage image) { return GetImageState(image)->acquired; });
         if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
-            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                             HandleToUint64(swapchain), kVUID_Core_DrawState_SwapchainTooManyImages,
                             "%s: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")", func_name,
                             acquired_images);
@@ -12856,7 +12210,7 @@
     }
 
     if (swapchain_data && swapchain_data->images.size() == 0) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                         HandleToUint64(swapchain), kVUID_Core_DrawState_SwapchainImagesNotFound,
                         "%s: No images found to acquire from. Application probably did not call "
                         "vkGetSwapchainImagesKHR after swapchain creation.",
@@ -12865,9 +12219,23 @@
     return skip;
 }
 
-static void PostCallRecordCommonAcquireNextImage(layer_data *dev_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
-                                                 VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
-    auto pFence = GetFenceNode(dev_data, fence);
+bool CoreChecks::PreCallValidateAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                                    VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateAcquireNextImage(device_data, device, swapchain, timeout, semaphore, fence, pImageIndex,
+                                    "vkAcquireNextImageKHR");
+}
+
+bool CoreChecks::PreCallValidateAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo,
+                                                     uint32_t *pImageIndex) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateAcquireNextImage(device_data, device, pAcquireInfo->swapchain, pAcquireInfo->timeout, pAcquireInfo->semaphore,
+                                    pAcquireInfo->fence, pImageIndex, "vkAcquireNextImage2KHR");
+}
+
+void CoreChecks::RecordAcquireNextImageState(layer_data *device_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                             VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
+    auto pFence = GetFenceNode(fence);
     if (pFence && pFence->scope == kSyncScopeInternal) {
         // Treat as inflight since it is valid to wait on this fence, even in cases where it is technically a temporary
         // import
@@ -12875,7 +12243,7 @@
         pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
     }
 
-    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
+    auto pSemaphore = GetSemaphoreNode(semaphore);
     if (pSemaphore && pSemaphore->scope == kSyncScopeInternal) {
         // Treat as signaled since it is valid to wait on this semaphore, even in cases where it is technically a
         // temporary import
@@ -12884,10 +12252,10 @@
     }
 
     // Mark the image as acquired.
-    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
+    auto swapchain_data = GetSwapchainNode(swapchain);
     if (swapchain_data && (swapchain_data->images.size() > *pImageIndex)) {
         auto image = swapchain_data->images[*pImageIndex];
-        auto image_state = GetImageState(dev_data, image);
+        auto image_state = GetImageState(image);
         if (image_state) {
             image_state->acquired = true;
             image_state->shared_presentable = swapchain_data->shared_presentable;
@@ -12895,116 +12263,35 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
-                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCommonAcquireNextImage(dev_data, device, swapchain, timeout, semaphore, fence, pImageIndex,
-                                                      "vkAcquireNextImageKHR");
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
-
-    lock.lock();
-    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
-        PostCallRecordCommonAcquireNextImage(dev_data, device, swapchain, timeout, semaphore, fence, pImageIndex);
-    }
-    lock.unlock();
-
-    return result;
+void CoreChecks::PostCallRecordAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if ((VK_SUCCESS != result) && (VK_SUBOPTIMAL_KHR != result)) return;
+    RecordAcquireNextImageState(device_data, device, swapchain, timeout, semaphore, fence, pImageIndex);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo,
-                                                    uint32_t *pImageIndex) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip =
-        PreCallValidateCommonAcquireNextImage(dev_data, device, pAcquireInfo->swapchain, pAcquireInfo->timeout,
-                                              pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex, "vkAcquireNextImage2KHR");
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkResult result = dev_data->dispatch_table.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
-
-    lock.lock();
-    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
-        PostCallRecordCommonAcquireNextImage(dev_data, device, pAcquireInfo->swapchain, pAcquireInfo->timeout,
-                                             pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex);
-        // TODO: consider physical device masks
-    }
-    lock.unlock();
-
-    return result;
+void CoreChecks::PostCallRecordAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo,
+                                                    uint32_t *pImageIndex, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if ((VK_SUCCESS != result) && (VK_SUBOPTIMAL_KHR != result)) return;
+    RecordAcquireNextImageState(device_data, device, pAcquireInfo->swapchain, pAcquireInfo->timeout, pAcquireInfo->semaphore,
+                                pAcquireInfo->fence, pImageIndex);
 }
 
-static bool PreCallValidateEnumeratePhysicalDevices(instance_layer_data *instance_data, uint32_t *pPhysicalDeviceCount) {
-    bool skip = false;
-    if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
-        // Flag warning here. You can call this without having queried the count, but it may not be
-        // robust on platforms with multiple physical devices.
-        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0,
-                        kVUID_Core_DevLimit_MissingQueryCount,
-                        "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first call "
-                        "vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
-    }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
-    else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
-        // Having actual count match count from app is not a requirement, so this can be a warning
-        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, kVUID_Core_DevLimit_CountMismatch,
-                        "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count supported by "
-                        "this instance is %u.",
-                        *pPhysicalDeviceCount, instance_data->physical_devices_count);
-    }
-    return skip;
-}
-
-static void PreCallRecordEnumeratePhysicalDevices(instance_layer_data *instance_data) {
-    instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
-}
-
-static void PostCallRecordEnumeratePhysicalDevices(instance_layer_data *instance_data, const VkResult &result,
-                                                   uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) {
-    if (NULL == pPhysicalDevices) {
-        instance_data->physical_devices_count = *pPhysicalDeviceCount;
-    } else if (result == VK_SUCCESS) {  // Save physical devices
+void CoreChecks::PostCallRecordEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
+                                                        VkPhysicalDevice *pPhysicalDevices, VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    if ((NULL != pPhysicalDevices) && ((result == VK_SUCCESS || result == VK_INCOMPLETE))) {
         for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
             auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
             phys_device_state.phys_device = pPhysicalDevices[i];
             // Init actual features for each physical device
-            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features2.features);
+            instance_data->instance_dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i],
+                                                                             &phys_device_state.features2.features);
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
-                                                        VkPhysicalDevice *pPhysicalDevices) {
-    bool skip = false;
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    assert(instance_data);
-
-    unique_lock_t lock(global_lock);
-    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
-    if (pPhysicalDevices) {
-        skip |= PreCallValidateEnumeratePhysicalDevices(instance_data, pPhysicalDeviceCount);
-    }
-    PreCallRecordEnumeratePhysicalDevices(instance_data);
-    lock.unlock();
-
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
-
-    lock.lock();
-    PostCallRecordEnumeratePhysicalDevices(instance_data, result, pPhysicalDeviceCount, pPhysicalDevices);
-    return result;
-}
-
 // Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
 static bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
                                                                  PHYSICAL_DEVICE_STATE *pd_state,
@@ -13037,22 +12324,37 @@
     return skip;
 }
 
-static bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
-                                                                  PHYSICAL_DEVICE_STATE *pd_state,
-                                                                  uint32_t *pQueueFamilyPropertyCount,
-                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
-    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
+bool CoreChecks::PreCallValidateGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
+                                                                       uint32_t *pQueueFamilyPropertyCount,
+                                                                       VkQueueFamilyProperties *pQueueFamilyProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    assert(physical_device_state);
+    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, *pQueueFamilyPropertyCount,
                                                                 (nullptr == pQueueFamilyProperties),
                                                                 "vkGetPhysicalDeviceQueueFamilyProperties()");
 }
 
-static bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(instance_layer_data *instance_data,
-                                                                   PHYSICAL_DEVICE_STATE *pd_state,
-                                                                   uint32_t *pQueueFamilyPropertyCount,
-                                                                   VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
+bool CoreChecks::PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
+                                                                        uint32_t *pQueueFamilyPropertyCount,
+                                                                        VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    assert(physical_device_state);
+    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, *pQueueFamilyPropertyCount,
                                                                 (nullptr == pQueueFamilyProperties),
-                                                                "vkGetPhysicalDeviceQueueFamilyProperties2[KHR]()");
+                                                                "vkGetPhysicalDeviceQueueFamilyProperties2()");
+}
+
+bool CoreChecks::PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t *pQueueFamilyPropertyCount,
+                                                                           VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    assert(physical_device_state);
+    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, *pQueueFamilyPropertyCount,
+                                                                (nullptr == pQueueFamilyProperties),
+                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
 }
 
 // Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
@@ -13073,106 +12375,47 @@
     }
 }
 
-static void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
-                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
+void CoreChecks::PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
+                                                                      uint32_t *pQueueFamilyPropertyCount,
+                                                                      VkQueueFamilyProperties *pQueueFamilyProperties) {
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    assert(physical_device_state);
     VkQueueFamilyProperties2KHR *pqfp = nullptr;
     std::vector<VkQueueFamilyProperties2KHR> qfp;
-    qfp.resize(count);
+    qfp.resize(*pQueueFamilyPropertyCount);
     if (pQueueFamilyProperties) {
-        for (uint32_t i = 0; i < count; ++i) {
+        for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) {
             qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
             qfp[i].pNext = nullptr;
             qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
         }
         pqfp = qfp.data();
     }
-    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
+    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount, pqfp);
 }
 
-static void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
-                                                                  VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
-}
-
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
-                                                                  uint32_t *pQueueFamilyPropertyCount,
-                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+void CoreChecks::PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
+                                                                       uint32_t *pQueueFamilyPropertyCount,
+                                                                       VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     assert(physical_device_state);
-    unique_lock_t lock(global_lock);
-
-    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state,
-                                                                      pQueueFamilyPropertyCount, pQueueFamilyProperties);
-
-    lock.unlock();
-
-    if (skip) return;
-
-    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
-                                                                         pQueueFamilyProperties);
-
-    lock.lock();
-    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount, pQueueFamilyProperties);
+    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount,
+                                                            pQueueFamilyProperties);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
-                                                                   uint32_t *pQueueFamilyPropertyCount,
-                                                                   VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+void CoreChecks::PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                          uint32_t *pQueueFamilyPropertyCount,
+                                                                          VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     assert(physical_device_state);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(instance_data, physical_device_state,
-                                                                       pQueueFamilyPropertyCount, pQueueFamilyProperties);
-    lock.unlock();
-    if (skip) return;
-
-    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount,
-                                                                          pQueueFamilyProperties);
-    lock.lock();
-    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(physical_device_state, *pQueueFamilyPropertyCount,
-                                                          pQueueFamilyProperties);
+    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount,
+                                                            pQueueFamilyProperties);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
-                                                                      uint32_t *pQueueFamilyPropertyCount,
-                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
-    assert(physical_device_state);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(instance_data, physical_device_state,
-                                                                       pQueueFamilyPropertyCount, pQueueFamilyProperties);
-    lock.unlock();
-    if (skip) return;
-
-    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
-                                                                             pQueueFamilyProperties);
-    lock.lock();
-    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(physical_device_state, *pQueueFamilyPropertyCount,
-                                                          pQueueFamilyProperties);
-}
-
-template <typename TCreateInfo, typename FPtr>
-static VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
-                              VkSurfaceKHR *pSurface, FPtr fptr) {
+bool CoreChecks::PreCallValidateDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
+                                                  const VkAllocationCallbacks *pAllocator) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    // Call down the call chain:
-    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
-
-    if (result == VK_SUCCESS) {
-        unique_lock_t lock(global_lock);
-        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
-        lock.unlock();
-    }
-
-    return result;
-}
-
-static bool PreCallValidateDestroySurfaceKHR(instance_layer_data *instance_data, VkInstance instance, VkSurfaceKHR surface) {
-    auto surface_state = GetSurfaceState(instance_data, surface);
+    auto surface_state = GetSurfaceState(surface);
     bool skip = false;
     if ((surface_state) && (surface_state->swapchain)) {
         skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
@@ -13182,331 +12425,194 @@
     return skip;
 }
 
-static void PreCallRecordValidateDestroySurfaceKHR(instance_layer_data *instance_data, VkSurfaceKHR surface) {
+void CoreChecks::PreCallRecordValidateDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
+                                                        const VkAllocationCallbacks *pAllocator) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
     instance_data->surface_map.erase(surface);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateDestroySurfaceKHR(instance_data, instance, surface);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordValidateDestroySurfaceKHR(instance_data, surface);
-    lock.unlock();
-    if (!skip) {
-        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
-    }
+static void RecordVulkanSurface(instance_layer_data *instance_data, VkSurfaceKHR *pSurface) {
+    instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
+void CoreChecks::PostCallRecordCreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                            VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
-VKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
-                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
+void CoreChecks::PostCallRecordCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
+                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                       VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 #endif  // VK_USE_PLATFORM_ANDROID_KHR
 
 #ifdef VK_USE_PLATFORM_IOS_MVK
-VKAPI_ATTR VkResult VKAPI_CALL CreateIOSSurfaceMVK(VkInstance instance, const VkIOSSurfaceCreateInfoMVK *pCreateInfo,
-                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateIOSSurfaceMVK);
+void CoreChecks::PostCallRecordCreateIOSSurfaceMVK(VkInstance instance, const VkIOSSurfaceCreateInfoMVK *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                   VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 #endif  // VK_USE_PLATFORM_IOS_MVK
 
 #ifdef VK_USE_PLATFORM_MACOS_MVK
-VKAPI_ATTR VkResult VKAPI_CALL CreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo,
-                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMacOSSurfaceMVK);
+void CoreChecks::PostCallRecordCreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                     VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 #endif  // VK_USE_PLATFORM_MACOS_MVK
 
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
-VKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
-                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
+void CoreChecks::PostCallRecordCreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
+                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                       VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 
-static bool PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(instance_layer_data *instance_data,
-                                                                          VkPhysicalDevice physicalDevice,
-                                                                          uint32_t queueFamilyIndex) {
-    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+bool CoreChecks::PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
+                                                                               uint32_t queueFamilyIndex,
+                                                                               struct wl_display *display) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    const auto pd_state = GetPhysicalDeviceState(physicalDevice);
     return ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex,
                                              "VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-queueFamilyIndex-01306",
                                              "vkGetPhysicalDeviceWaylandPresentationSupportKHR", "queueFamilyIndex");
 }
-
-VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
-                                                                              uint32_t queueFamilyIndex,
-                                                                              struct wl_display *display) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(instance_data, physicalDevice, queueFamilyIndex);
-    lock.unlock();
-
-    if (skip) return VK_FALSE;
-
-    // Call down the call chain:
-    VkBool32 result =
-        instance_data->dispatch_table.GetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, display);
-
-    return result;
-}
 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-VKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
-                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
+void CoreChecks::PostCallRecordCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                     VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 
-static bool PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(instance_layer_data *instance_data,
-                                                                        VkPhysicalDevice physicalDevice,
-                                                                        uint32_t queueFamilyIndex) {
-    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+bool CoreChecks::PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
+                                                                             uint32_t queueFamilyIndex) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    const auto pd_state = GetPhysicalDeviceState(physicalDevice);
     return ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex,
                                              "VUID-vkGetPhysicalDeviceWin32PresentationSupportKHR-queueFamilyIndex-01309",
                                              "vkGetPhysicalDeviceWin32PresentationSupportKHR", "queueFamilyIndex");
 }
-
-VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
-                                                                            uint32_t queueFamilyIndex) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(instance_data, physicalDevice, queueFamilyIndex);
-    lock.unlock();
-
-    if (skip) return VK_FALSE;
-
-    // Call down the call chain:
-    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
-
-    return result;
-}
 #endif  // VK_USE_PLATFORM_WIN32_KHR
 
 #ifdef VK_USE_PLATFORM_XCB_KHR
-VKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
-                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
+void CoreChecks::PostCallRecordCreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                   VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 
-static bool PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(instance_layer_data *instance_data,
-                                                                      VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) {
-    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+bool CoreChecks::PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t queueFamilyIndex, xcb_connection_t *connection,
+                                                                           xcb_visualid_t visual_id) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    const auto pd_state = GetPhysicalDeviceState(physicalDevice);
     return ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex,
                                              "VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-queueFamilyIndex-01312",
                                              "vkGetPhysicalDeviceXcbPresentationSupportKHR", "queueFamilyIndex");
 }
-
-VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
-                                                                          uint32_t queueFamilyIndex, xcb_connection_t *connection,
-                                                                          xcb_visualid_t visual_id) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(instance_data, physicalDevice, queueFamilyIndex);
-    lock.unlock();
-
-    if (skip) return VK_FALSE;
-
-    // Call down the call chain:
-    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex,
-                                                                                               connection, visual_id);
-
-    return result;
-}
 #endif  // VK_USE_PLATFORM_XCB_KHR
 
 #ifdef VK_USE_PLATFORM_XLIB_KHR
-VKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
+void CoreChecks::PostCallRecordCreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface,
+                                                    VkResult result) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordVulkanSurface(instance_data, pSurface);
 }
 
-static bool PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(instance_layer_data *instance_data,
-                                                                       VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) {
-    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+bool CoreChecks::PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
+                                                                            uint32_t queueFamilyIndex, Display *dpy,
+                                                                            VisualID visualID) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    const auto pd_state = GetPhysicalDeviceState(physicalDevice);
     return ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex,
                                              "VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-queueFamilyIndex-01315",
                                              "vkGetPhysicalDeviceXlibPresentationSupportKHR", "queueFamilyIndex");
 }
-
-VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
-                                                                           uint32_t queueFamilyIndex, Display *dpy,
-                                                                           VisualID visualID) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(instance_data, physicalDevice, queueFamilyIndex);
-    lock.unlock();
-
-    if (skip) return VK_FALSE;
-
-    // Call down the call chain:
-    VkBool32 result =
-        instance_data->dispatch_table.GetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, dpy, visualID);
-
-    return result;
-}
 #endif  // VK_USE_PLATFORM_XLIB_KHR
 
-static void PostCallRecordGetPhysicalDeviceSurfaceCapabilitiesKHR(instance_layer_data *instance_data,
-                                                                  VkPhysicalDevice physicalDevice,
-                                                                  VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities,
+                                                                       VkResult result) {
+    if (VK_SUCCESS != result) return;
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
     physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
-                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    auto result =
-        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
-
-    unique_lock_t lock(global_lock);
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetPhysicalDeviceSurfaceCapabilitiesKHR(instance_data, physicalDevice, pSurfaceCapabilities);
-    }
-
-    return result;
-}
-
-static void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instance_layer_data *instanceData,
-                                                                   VkPhysicalDevice physicalDevice,
-                                                                   VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
-    unique_lock_t lock(global_lock);
-    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
-    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
-    physicalDeviceState->surfaceCapabilities = pSurfaceCapabilities->surfaceCapabilities;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
                                                                         const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
-                                                                        VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
-    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    auto result =
-        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instanceData, physicalDevice, pSurfaceCapabilities);
-    }
-
-    return result;
+                                                                        VkSurfaceCapabilities2KHR *pSurfaceCapabilities,
+                                                                        VkResult result) {
+    if (VK_SUCCESS != result) return;
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
+    physical_device_state->surfaceCapabilities = pSurfaceCapabilities->surfaceCapabilities;
 }
 
-static void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instance_layer_data *instanceData,
-                                                                   VkPhysicalDevice physicalDevice,
-                                                                   VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
-    unique_lock_t lock(global_lock);
-    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
-    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
-    physicalDeviceState->surfaceCapabilities.minImageCount = pSurfaceCapabilities->minImageCount;
-    physicalDeviceState->surfaceCapabilities.maxImageCount = pSurfaceCapabilities->maxImageCount;
-    physicalDeviceState->surfaceCapabilities.currentExtent = pSurfaceCapabilities->currentExtent;
-    physicalDeviceState->surfaceCapabilities.minImageExtent = pSurfaceCapabilities->minImageExtent;
-    physicalDeviceState->surfaceCapabilities.maxImageExtent = pSurfaceCapabilities->maxImageExtent;
-    physicalDeviceState->surfaceCapabilities.maxImageArrayLayers = pSurfaceCapabilities->maxImageArrayLayers;
-    physicalDeviceState->surfaceCapabilities.supportedTransforms = pSurfaceCapabilities->supportedTransforms;
-    physicalDeviceState->surfaceCapabilities.currentTransform = pSurfaceCapabilities->currentTransform;
-    physicalDeviceState->surfaceCapabilities.supportedCompositeAlpha = pSurfaceCapabilities->supportedCompositeAlpha;
-    physicalDeviceState->surfaceCapabilities.supportedUsageFlags = pSurfaceCapabilities->supportedUsageFlags;
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities,
+                                                                        VkResult result) {
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
+    physical_device_state->surfaceCapabilities.minImageCount = pSurfaceCapabilities->minImageCount;
+    physical_device_state->surfaceCapabilities.maxImageCount = pSurfaceCapabilities->maxImageCount;
+    physical_device_state->surfaceCapabilities.currentExtent = pSurfaceCapabilities->currentExtent;
+    physical_device_state->surfaceCapabilities.minImageExtent = pSurfaceCapabilities->minImageExtent;
+    physical_device_state->surfaceCapabilities.maxImageExtent = pSurfaceCapabilities->maxImageExtent;
+    physical_device_state->surfaceCapabilities.maxImageArrayLayers = pSurfaceCapabilities->maxImageArrayLayers;
+    physical_device_state->surfaceCapabilities.supportedTransforms = pSurfaceCapabilities->supportedTransforms;
+    physical_device_state->surfaceCapabilities.currentTransform = pSurfaceCapabilities->currentTransform;
+    physical_device_state->surfaceCapabilities.supportedCompositeAlpha = pSurfaceCapabilities->supportedCompositeAlpha;
+    physical_device_state->surfaceCapabilities.supportedUsageFlags = pSurfaceCapabilities->supportedUsageFlags;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
-                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
-    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    auto result =
-        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
-
-    if (result == VK_SUCCESS) {
-        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instanceData, physicalDevice, pSurfaceCapabilities);
-    }
-
-    return result;
-}
-
-static bool PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(instance_layer_data *instance_data,
-                                                              PHYSICAL_DEVICE_STATE *physical_device_state,
-                                                              uint32_t queueFamilyIndex) {
+bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                                   VkSurfaceKHR surface, VkBool32 *pSupported) {
+    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    const auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     return ValidatePhysicalDeviceQueueFamily(instance_data, physical_device_state, queueFamilyIndex,
                                              "VUID-vkGetPhysicalDeviceSurfaceSupportKHR-queueFamilyIndex-01269",
                                              "vkGetPhysicalDeviceSurfaceSupportKHR", "queueFamilyIndex");
 }
 
-static void PostCallRecordGetPhysicalDeviceSurfaceSupportKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
-                                                             uint32_t queueFamilyIndex, VkSurfaceKHR surface,
-                                                             VkBool32 *pSupported) {
-    auto surface_state = GetSurfaceState(instance_data, surface);
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                                  VkSurfaceKHR surface, VkBool32 *pSupported, VkResult result) {
+    if (VK_SUCCESS != result) return;
+    auto surface_state = GetSurfaceState(surface);
     surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported == VK_TRUE);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
-                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
-    bool skip = false;
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                       uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes,
+                                                                       VkResult result) {
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
 
-    unique_lock_t lock(global_lock);
-    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+    // TODO: This isn't quite right -- available modes may differ by surface AND physical device.
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
 
-    skip |= PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(instance_data, pd_state, queueFamilyIndex);
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    auto result =
-        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
-
-    if (result == VK_SUCCESS) {
-        lock.lock();
-        PostCallRecordGetPhysicalDeviceSurfaceSupportKHR(instance_data, physicalDevice, queueFamilyIndex, surface, pSupported);
-    }
-
-    return result;
-}
-
-static bool PreCallValidateGetPhysicalDeviceSurfacePresentModesKHR(instance_layer_data *instance_data,
-                                                                   PHYSICAL_DEVICE_STATE *physical_device_state,
-                                                                   CALL_STATE &call_state, VkPhysicalDevice physicalDevice,
-                                                                   uint32_t *pPresentModeCount) {
-    // Compare the preliminary value of *pPresentModeCount with the value this time:
-    auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
-    bool skip = false;
-    switch (call_state) {
-        case UNCALLED:
-            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
-                            kVUID_Core_DevLimit_MustQueryCount,
-                            "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior "
-                            "positive value has been seen for pPresentModeCount.");
-            break;
-        default:
-            // both query count and query details
-            if (*pPresentModeCount != prev_mode_count) {
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
-                                kVUID_Core_DevLimit_CountMismatch,
-                                "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that differs "
-                                "from the value (%u) that was returned when pPresentModes was NULL.",
-                                *pPresentModeCount, prev_mode_count);
-            }
-            break;
-    }
-    return skip;
-}
-
-static void PostCallRecordGetPhysicalDeviceSurfacePresentModesKHR(PHYSICAL_DEVICE_STATE *physical_device_state,
-                                                                  CALL_STATE &call_state, uint32_t *pPresentModeCount,
-                                                                  VkPresentModeKHR *pPresentModes) {
     if (*pPresentModeCount) {
         if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
         if (*pPresentModeCount > physical_device_state->present_modes.size())
@@ -13520,45 +12626,17 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
-                                                                       uint32_t *pPresentModeCount,
-                                                                       VkPresentModeKHR *pPresentModes) {
-    bool skip = false;
+bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                   uint32_t *pSurfaceFormatCount,
+                                                                   VkSurfaceFormatKHR *pSurfaceFormats) {
     auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    unique_lock_t lock(global_lock);
-    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
-    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
-
-    if (pPresentModes) {
-        skip |= PreCallValidateGetPhysicalDeviceSurfacePresentModesKHR(instance_data, physical_device_state, call_state,
-                                                                       physicalDevice, pPresentModeCount);
-    }
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
-                                                                                        pPresentModes);
-
-    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-        lock.lock();
-        PostCallRecordGetPhysicalDeviceSurfacePresentModesKHR(physical_device_state, call_state, pPresentModeCount, pPresentModes);
-    }
-
-    return result;
-}
-
-static bool PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(instance_layer_data *instance_data,
-                                                              PHYSICAL_DEVICE_STATE *physical_device_state, CALL_STATE &call_state,
-                                                              VkPhysicalDevice physicalDevice, uint32_t *pSurfaceFormatCount) {
-    auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
+    if (!pSurfaceFormats) return false;
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
     bool skip = false;
-
     switch (call_state) {
         case UNCALLED:
-            // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
-            // didn't
+            // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application didn't
             // previously call this function with a NULL value of pSurfaceFormats:
             skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
@@ -13567,6 +12645,7 @@
                             "positive value has been seen for pSurfaceFormats.");
             break;
         default:
+            auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
             if (prev_format_count != *pSurfaceFormatCount) {
                 skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
@@ -13581,8 +12660,14 @@
     return skip;
 }
 
-static void PostCallRecordGetPhysicalDeviceSurfaceFormatsKHR(PHYSICAL_DEVICE_STATE *physical_device_state, CALL_STATE &call_state,
-                                                             uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) {
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                  uint32_t *pSurfaceFormatCount,
+                                                                  VkSurfaceFormatKHR *pSurfaceFormats, VkResult result) {
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
+
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
+    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
+
     if (*pSurfaceFormatCount) {
         if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
         if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
@@ -13596,38 +12681,13 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
-                                                                  uint32_t *pSurfaceFormatCount,
-                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
-    bool skip = false;
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    unique_lock_t lock(global_lock);
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
-    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
+void CoreChecks::PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
+                                                                   const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
+                                                                   uint32_t *pSurfaceFormatCount,
+                                                                   VkSurfaceFormat2KHR *pSurfaceFormats, VkResult result) {
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
 
-    if (pSurfaceFormats) {
-        skip |= PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(instance_data, physical_device_state, call_state, physicalDevice,
-                                                                  pSurfaceFormatCount);
-    }
-    lock.unlock();
-
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    // Call down the call chain:
-    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
-                                                                                   pSurfaceFormats);
-
-    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-        lock.lock();
-        PostCallRecordGetPhysicalDeviceSurfaceFormatsKHR(physical_device_state, call_state, pSurfaceFormatCount, pSurfaceFormats);
-    }
-    return result;
-}
-
-static void PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instance_layer_data *instanceData, VkPhysicalDevice physicalDevice,
-                                                              uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) {
-    unique_lock_t lock(global_lock);
-    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
+    auto physicalDeviceState = GetPhysicalDeviceState(physicalDevice);
     if (*pSurfaceFormatCount) {
         if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
             physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
@@ -13645,356 +12705,100 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
-                                                                   const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
-                                                                   uint32_t *pSurfaceFormatCount,
-                                                                   VkSurfaceFormat2KHR *pSurfaceFormats) {
-    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    auto result = instanceData->dispatch_table.GetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, pSurfaceInfo,
-                                                                                   pSurfaceFormatCount, pSurfaceFormats);
-    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-        PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instanceData, physicalDevice, pSurfaceFormatCount, pSurfaceFormats);
-    }
-    return result;
+void CoreChecks::PreCallRecordQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    BeginQueueDebugUtilsLabel(device_data->report_data, queue, pLabelInfo);
 }
 
-// VK_EXT_debug_utils commands
-static void PreCallRecordSetDebugUtilsObectNameEXT(layer_data *dev_data, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
-    if (pNameInfo->pObjectName) {
-        lock_guard_t lock(global_lock);
-        dev_data->report_data->debugUtilsObjectNameMap->insert(
-            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->objectHandle, pNameInfo->pObjectName));
-    } else {
-        lock_guard_t lock(global_lock);
-        dev_data->report_data->debugUtilsObjectNameMap->erase(pNameInfo->objectHandle);
-    }
+void CoreChecks::PostCallRecordQueueEndDebugUtilsLabelEXT(VkQueue queue) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    EndQueueDebugUtilsLabel(device_data->report_data, queue);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_SUCCESS;
-
-    PreCallRecordSetDebugUtilsObectNameEXT(dev_data, pNameInfo);
-
-    if (nullptr != dev_data->dispatch_table.SetDebugUtilsObjectNameEXT) {
-        result = dev_data->dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo);
-    }
-    return result;
+void CoreChecks::PreCallRecordQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    InsertQueueDebugUtilsLabel(device_data->report_data, queue, pLabelInfo);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = VK_SUCCESS;
-    if (nullptr != dev_data->dispatch_table.SetDebugUtilsObjectTagEXT) {
-        result = dev_data->dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo);
-    }
-    return result;
+void CoreChecks::PreCallRecordCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    BeginCmdDebugUtilsLabel(device_data->report_data, commandBuffer, pLabelInfo);
 }
 
-static void PreCallRecordQueueBeginDebugUtilsLabelEXT(layer_data *dev_data, VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    BeginQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
+void CoreChecks::PostCallRecordCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    EndCmdDebugUtilsLabel(device_data->report_data, commandBuffer);
 }
 
-VKAPI_ATTR void VKAPI_CALL QueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    PreCallRecordQueueBeginDebugUtilsLabelEXT(dev_data, queue, pLabelInfo);
-    lock.unlock();
-    if (nullptr != dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
-    }
+void CoreChecks::PreCallRecordCmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    InsertCmdDebugUtilsLabel(device_data->report_data, commandBuffer, pLabelInfo);
 }
 
-static void PostCallRecordQueueEndDebugUtilsLabelEXT(layer_data *dev_data, VkQueue queue) {
-    EndQueueDebugUtilsLabel(dev_data->report_data, queue);
-}
-
-VKAPI_ATTR void VKAPI_CALL QueueEndDebugUtilsLabelEXT(VkQueue queue) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    if (nullptr != dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT(queue);
-    }
-    lock_guard_t lock(global_lock);
-    PostCallRecordQueueEndDebugUtilsLabelEXT(dev_data, queue);
-}
-
-static void PreCallRecordQueueInsertDebugUtilsLabelEXT(layer_data *dev_data, VkQueue queue,
-                                                       const VkDebugUtilsLabelEXT *pLabelInfo) {
-    InsertQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
-}
-
-VKAPI_ATTR void VKAPI_CALL QueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    PreCallRecordQueueInsertDebugUtilsLabelEXT(dev_data, queue, pLabelInfo);
-    lock.unlock();
-    if (nullptr != dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
-    }
-}
-
-static void PreCallRecordCmdBeginDebugUtilsLabelEXT(layer_data *dev_data, VkCommandBuffer commandBuffer,
-                                                    const VkDebugUtilsLabelEXT *pLabelInfo) {
-    BeginCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    PreCallRecordCmdBeginDebugUtilsLabelEXT(dev_data, commandBuffer, pLabelInfo);
-    lock.unlock();
-    if (nullptr != dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
-    }
-}
-
-static void PostCallRecordCmdEndDebugUtilsLabelEXT(layer_data *dev_data, VkCommandBuffer commandBuffer) {
-    EndCmdDebugUtilsLabel(dev_data->report_data, commandBuffer);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    if (nullptr != dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT(commandBuffer);
-    }
-    lock_guard_t lock(global_lock);
-    PostCallRecordCmdEndDebugUtilsLabelEXT(dev_data, commandBuffer);
-}
-
-static void PreCallRecordCmdInsertDebugUtilsLabelEXT(layer_data *dev_data, VkCommandBuffer commandBuffer,
-                                                     const VkDebugUtilsLabelEXT *pLabelInfo) {
-    InsertCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    PreCallRecordCmdInsertDebugUtilsLabelEXT(dev_data, commandBuffer, pLabelInfo);
-    lock.unlock();
-    if (nullptr != dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT) {
-        dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
-    }
-}
-
-static VkResult PostCallRecordCreateDebugUtilsMessengerEXT(instance_layer_data *instance_data,
-                                                           const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                           const VkAllocationCallbacks *pAllocator,
-                                                           VkDebugUtilsMessengerEXT *pMessenger) {
-    return layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
+void CoreChecks::PostCallRecordCreateDebugUtilsMessengerEXT(VkInstance instance,
                                                             const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
                                                             const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugUtilsMessengerEXT *pMessenger) {
+                                                            VkDebugUtilsMessengerEXT *pMessenger, VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult result = instance_data->dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-
-    if (VK_SUCCESS == result) {
-        result = PostCallRecordCreateDebugUtilsMessengerEXT(instance_data, pCreateInfo, pAllocator, pMessenger);
-    }
-    return result;
+    if (VK_SUCCESS != result) return;
+    layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
 }
 
-static void PostCallRecordDestroyDebugUtilsMessengerEXT(instance_layer_data *instance_data, VkDebugUtilsMessengerEXT messenger,
-                                                        const VkAllocationCallbacks *pAllocator) {
+void CoreChecks::PostCallRecordDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                             const VkAllocationCallbacks *pAllocator) {
+    if (!messenger) return;
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
     layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                         const VkAllocationCallbacks *pAllocator) {
+void CoreChecks::PostCallRecordDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
+                                                             const VkAllocationCallbacks *pAllocator) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-    PostCallRecordDestroyDebugUtilsMessengerEXT(instance_data, messenger, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-                                                      VkDebugUtilsMessageTypeFlagsEXT messageTypes,
-                                                      const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
-}
-
-// VK_EXT_debug_report commands
-static VkResult PostCallRecordCreateDebugReportCallbackEXT(instance_layer_data *instance_data,
-                                                           const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                           const VkAllocationCallbacks *pAllocator,
-                                                           VkDebugReportCallbackEXT *pMsgCallback) {
-    return layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
-                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugReportCallbackEXT *pMsgCallback) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-    if (VK_SUCCESS == res) {
-        lock_guard_t lock(global_lock);
-        res = PostCallRecordCreateDebugReportCallbackEXT(instance_data, pCreateInfo, pAllocator, pMsgCallback);
-    }
-    return res;
-}
-
-static void PostCallDestroyDebugReportCallbackEXT(instance_layer_data *instance_data, VkDebugReportCallbackEXT msgCallback,
-                                                  const VkAllocationCallbacks *pAllocator) {
     layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-    lock_guard_t lock(global_lock);
-    PostCallDestroyDebugReportCallbackEXT(instance_data, msgCallback, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                              VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                    VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
-        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
-
-    return VK_ERROR_LAYER_NOT_PRESENT;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
-                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
-        return util_GetExtensionProperties(1, device_extensions, pCount, pProperties);
-
-    assert(physicalDevice);
-
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
-}
-
-static bool PreCallValidateEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+static void PostRecordEnumeratePhysicalDeviceGroupsState(instance_layer_data *instance_data, uint32_t *pPhysicalDeviceGroupCount,
                                                          VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    bool skip = false;
-
-    if (instance_data) {
-        // For this instance, flag when EnumeratePhysicalDeviceGroups goes to QUERY_COUNT and then QUERY_DETAILS.
-        if (NULL != pPhysicalDeviceGroupProperties) {
-            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
-                // Flag warning here. You can call this without having queried the count, but it may not be
-                // robust on platforms with multiple physical devices.
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, kVUID_Core_DevLimit_MissingQueryCount,
-                                "Call sequence has vkEnumeratePhysicalDeviceGroups() w/ non-NULL "
-                                "pPhysicalDeviceGroupProperties. You should first call vkEnumeratePhysicalDeviceGroups() w/ "
-                                "NULL pPhysicalDeviceGroupProperties to query pPhysicalDeviceGroupCount.");
-            }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
-            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
-                // Having actual count match count from app is not a requirement, so this can be a warning
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, kVUID_Core_DevLimit_CountMismatch,
-                                "Call to vkEnumeratePhysicalDeviceGroups() w/ pPhysicalDeviceGroupCount value %u, but actual count "
-                                "supported by this instance is %u.",
-                                *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
-            }
-        }
-    } else {
-        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0,
-                kVUID_Core_DevLimit_InvalidInstance,
-                "Invalid instance (0x%" PRIx64 ") passed into vkEnumeratePhysicalDeviceGroups().", HandleToUint64(instance));
-    }
-
-    return skip;
-}
-
-static void PreCallRecordEnumeratePhysicalDeviceGroups(instance_layer_data *instance_data,
-                                                       VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties) {
-    if (instance_data) {
-        // For this instance, flag when EnumeratePhysicalDeviceGroups goes to QUERY_COUNT and then QUERY_DETAILS.
-        if (NULL == pPhysicalDeviceGroupProperties) {
-            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
-        } else {
-            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
-        }
-    }
-}
-
-static void PostCallRecordEnumeratePhysicalDeviceGroups(instance_layer_data *instance_data, uint32_t *pPhysicalDeviceGroupCount,
-                                                        VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties) {
-    if (NULL == pPhysicalDeviceGroupProperties) {
-        instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
-    } else {  // Save physical devices
+    if (NULL != pPhysicalDeviceGroupProperties) {
         for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
             for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
                 VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
                 auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
                 phys_device_state.phys_device = cur_phys_dev;
                 // Init actual features for each physical device
-                instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features2.features);
+                instance_data->instance_dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev,
+                                                                                 &phys_device_state.features2.features);
             }
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
-                                                             VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties) {
-    bool skip = false;
+void CoreChecks::PostCallRecordEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+                                                             VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties,
+                                                             VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    skip = PreCallValidateEnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    PreCallRecordEnumeratePhysicalDeviceGroups(instance_data, pPhysicalDeviceGroupProperties);
-    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount,
-                                                                                  pPhysicalDeviceGroupProperties);
-    if (result == VK_SUCCESS) {
-        PostCallRecordEnumeratePhysicalDeviceGroups(instance_data, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-    }
-    return result;
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
+    PostRecordEnumeratePhysicalDeviceGroupsState(instance_data, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHR(
-    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties) {
-    bool skip = false;
+void CoreChecks::PostCallRecordEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
+                                                                VkPhysicalDeviceGroupPropertiesKHR *pPhysicalDeviceGroupProperties,
+                                                                VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    skip = PreCallValidateEnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    PreCallRecordEnumeratePhysicalDeviceGroups(instance_data, pPhysicalDeviceGroupProperties);
-    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHR(instance, pPhysicalDeviceGroupCount,
-                                                                                     pPhysicalDeviceGroupProperties);
-    if (result == VK_SUCCESS) {
-        PostCallRecordEnumeratePhysicalDeviceGroups(instance_data, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-    }
-    return result;
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
+    PostRecordEnumeratePhysicalDeviceGroupsState(instance_data, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
 }
 
-static bool PreCallValidateCreateDescriptorUpdateTemplate(const char *func_name, layer_data *device_data,
-                                                          const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
-                                                          const VkAllocationCallbacks *pAllocator,
-                                                          VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+bool CoreChecks::ValidateDescriptorUpdateTemplate(const char *func_name, layer_data *device_data,
+                                                  const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo) {
     bool skip = false;
     const auto layout = GetDescriptorSetLayout(device_data, pCreateInfo->descriptorSetLayout);
     if (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET == pCreateInfo->templateType && !layout) {
         auto ds_uint = HandleToUint64(pCreateInfo->descriptorSetLayout);
         skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
                         ds_uint, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00350",
-                        "%s: Invalid pCreateInfo->descriptorSetLayout (%" PRIx64 ")", func_name, ds_uint);
+                        "%s: Invalid pCreateInfo->descriptorSetLayout (%s)", func_name,
+                        device_data->report_data->FormatHandle(ds_uint).c_str());
     } else if (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR == pCreateInfo->templateType) {
         auto bind_point = pCreateInfo->pipelineBindPoint;
         bool valid_bp = (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) || (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE);
@@ -14007,10 +12811,10 @@
         const auto pipeline_layout = GetPipelineLayout(device_data, pCreateInfo->pipelineLayout);
         if (!pipeline_layout) {
             uint64_t pl_uint = HandleToUint64(pCreateInfo->pipelineLayout);
-            skip |=
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
-                        pl_uint, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00352",
-                        "%s: Invalid pCreateInfo->pipelineLayout (%" PRIx64 ")", func_name, pl_uint);
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, pl_uint,
+                "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00352", "%s: Invalid pCreateInfo->pipelineLayout (%s)",
+                func_name, device_data->report_data->FormatHandle(pl_uint).c_str());
         } else {
             const uint32_t pd_set = pCreateInfo->set;
             if ((pd_set >= pipeline_layout->set_layouts.size()) || !pipeline_layout->set_layouts[pd_set] ||
@@ -14020,154 +12824,254 @@
                                 VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, pl_uint,
                                 "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00353",
                                 "%s: pCreateInfo->set (%" PRIu32
-                                ") does not refer to the push descriptor set layout for "
-                                "pCreateInfo->pipelineLayout (%" PRIx64 ").",
-                                func_name, pd_set, pl_uint);
+                                ") does not refer to the push descriptor set layout for pCreateInfo->pipelineLayout (%s).",
+                                func_name, pd_set, device_data->report_data->FormatHandle(pl_uint).c_str());
             }
         }
     }
     return skip;
 }
 
-static void PostCallRecordCreateDescriptorUpdateTemplate(layer_data *device_data,
-                                                         const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
-                                                         VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
-    // Shadow template createInfo for later updates
+bool CoreChecks::PreCallValidateCreateDescriptorUpdateTemplate(VkDevice device,
+                                                               const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
+                                                               const VkAllocationCallbacks *pAllocator,
+                                                               VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    bool skip = ValidateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplate()", device_data, pCreateInfo);
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCreateDescriptorUpdateTemplateKHR(VkDevice device,
+                                                                  const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
+                                                                  const VkAllocationCallbacks *pAllocator,
+                                                                  VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    bool skip = ValidateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplateKHR()", device_data, pCreateInfo);
+    return skip;
+}
+
+void CoreChecks::PreCallRecordDestroyDescriptorUpdateTemplate(VkDevice device,
+                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                              const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!descriptorUpdateTemplate) return;
+    device_data->desc_template_map.erase(descriptorUpdateTemplate);
+}
+
+void CoreChecks::PreCallRecordDestroyDescriptorUpdateTemplateKHR(VkDevice device,
+                                                                 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                                 const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!descriptorUpdateTemplate) return;
+    device_data->desc_template_map.erase(descriptorUpdateTemplate);
+}
+
+void RecordCreateDescriptorUpdateTemplateState(layer_data *device_data, const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
+                                               VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
     safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo);
     std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
     device_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplate(VkDevice device,
+void CoreChecks::PostCallRecordCreateDescriptorUpdateTemplate(VkDevice device,
                                                               const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
                                                               const VkAllocationCallbacks *pAllocator,
-                                                              VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+                                                              VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate,
+                                                              VkResult result) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplate()", device_data, pCreateInfo,
-                                                              pAllocator, pDescriptorUpdateTemplate);
-
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    if (!skip) {
-        lock.unlock();
-        result =
-            device_data->dispatch_table.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
-        if (VK_SUCCESS == result) {
-            lock.lock();
-            PostCallRecordCreateDescriptorUpdateTemplate(device_data, pCreateInfo, pDescriptorUpdateTemplate);
-        }
-    }
-    return result;
+    if (VK_SUCCESS != result) return;
+    RecordCreateDescriptorUpdateTemplateState(device_data, pCreateInfo, pDescriptorUpdateTemplate);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
+void CoreChecks::PostCallRecordCreateDescriptorUpdateTemplateKHR(VkDevice device,
                                                                  const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
                                                                  const VkAllocationCallbacks *pAllocator,
-                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate,
+                                                                 VkResult result) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCreateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplateKHR()", device_data, pCreateInfo,
-                                                              pAllocator, pDescriptorUpdateTemplate);
+    if (VK_SUCCESS != result) return;
+    RecordCreateDescriptorUpdateTemplateState(device_data, pCreateInfo, pDescriptorUpdateTemplate);
+}
 
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    if (!skip) {
-        lock.unlock();
-        result = device_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator,
-                                                                               pDescriptorUpdateTemplate);
-        if (VK_SUCCESS == result) {
-            lock.lock();
-            PostCallRecordCreateDescriptorUpdateTemplate(device_data, pCreateInfo, pDescriptorUpdateTemplate);
+bool CoreChecks::ValidateUpdateDescriptorSetWithTemplate(layer_data *device_data, VkDescriptorSet descriptorSet,
+                                                         VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                         const void *pData) {
+    bool skip = false;
+    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
+    if ((template_map_entry == device_data->desc_template_map.end()) || (template_map_entry->second.get() == nullptr)) {
+        // Object tracker will report errors for invalid descriptorUpdateTemplate values, avoiding a crash in release builds
+        // but retaining the assert as template support is new enough to want to investigate these in debug builds.
+        assert(0);
+    } else {
+        const TEMPLATE_STATE *template_state = template_map_entry->second.get();
+        // TODO: Validate template push descriptor updates
+        if (template_state->create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) {
+            skip = ValidateUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_state, pData);
         }
     }
-    return result;
+    return skip;
 }
 
-static void PreCallRecordDestroyDescriptorUpdateTemplate(layer_data *device_data,
-                                                         VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate) {
-    device_data->desc_template_map.erase(descriptorUpdateTemplate);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                           const VkAllocationCallbacks *pAllocator) {
+bool CoreChecks::PreCallValidateUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
+                                                                VkDescriptorUpdateTemplate descriptorUpdateTemplate,
+                                                                const void *pData) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordDestroyDescriptorUpdateTemplate(device_data, descriptorUpdateTemplate);
-    lock.unlock();
-    device_data->dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+    return ValidateUpdateDescriptorSetWithTemplate(device_data, descriptorSet, descriptorUpdateTemplate, pData);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
-                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                              const VkAllocationCallbacks *pAllocator) {
+bool CoreChecks::PreCallValidateUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
+                                                                   VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                                   const void *pData) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    unique_lock_t lock(global_lock);
-    // Pre-record to avoid Destroy/Create race
-    PreCallRecordDestroyDescriptorUpdateTemplate(device_data, descriptorUpdateTemplate);
-    lock.unlock();
-    device_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
+    return ValidateUpdateDescriptorSetWithTemplate(device_data, descriptorSet, descriptorUpdateTemplate, pData);
 }
 
-// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
-static void PostCallRecordUpdateDescriptorSetWithTemplate(layer_data *device_data, VkDescriptorSet descriptorSet,
-                                                          VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                          const void *pData) {
+void CoreChecks::RecordUpdateDescriptorSetWithTemplateState(layer_data *device_data, VkDescriptorSet descriptorSet,
+                                                            VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                            const void *pData) {
     auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
-    if (template_map_entry == device_data->desc_template_map.end()) {
+    if ((template_map_entry == device_data->desc_template_map.end()) || (template_map_entry->second.get() == nullptr)) {
         assert(0);
+    } else {
+        const TEMPLATE_STATE *template_state = template_map_entry->second.get();
+        // TODO: Record template push descriptor updates
+        if (template_state->create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) {
+            PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_state, pData);
+        }
     }
-
-    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
 }
 
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
-                                                           VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                           const void *pData) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    device_data->dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
-    unique_lock_t lock(global_lock);
-
-    PostCallRecordUpdateDescriptorSetWithTemplate(device_data, descriptorSet, descriptorUpdateTemplate, pData);
-}
-
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
-                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+void CoreChecks::PreCallRecordUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
+                                                              VkDescriptorUpdateTemplate descriptorUpdateTemplate,
                                                               const void *pData) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
-    unique_lock_t lock(global_lock);
-
-    PostCallRecordUpdateDescriptorSetWithTemplate(device_data, descriptorSet, descriptorUpdateTemplate, pData);
+    RecordUpdateDescriptorSetWithTemplateState(device_data, descriptorSet, descriptorUpdateTemplate, pData);
 }
 
-static bool PreCallValidateCmdPushDescriptorSetWithTemplateKHR(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    return ValidateCmd(dev_data, cb_state, CMD_PUSHDESCRIPTORSETWITHTEMPLATEKHR, "vkCmdPushDescriptorSetWithTemplateKHR()");
+void CoreChecks::PreCallRecordUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
+                                                                 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                                 const void *pData) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    RecordUpdateDescriptorSetWithTemplateState(device_data, descriptorSet, descriptorUpdateTemplate, pData);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
-                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
+static std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> GetDslFromPipelineLayout(PIPELINE_LAYOUT_NODE const *layout_data,
+                                                                                            uint32_t set) {
+    std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> dsl = nullptr;
+    if (layout_data && (set < layout_data->set_layouts.size())) {
+        dsl = layout_data->set_layouts[set];
+    }
+    return dsl;
+}
+
+bool CoreChecks::PreCallValidateCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
+                                                                    VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                                    VkPipelineLayout layout, uint32_t set, const void *pData) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    const char *const func_name = "vkPushDescriptorSetWithTemplateKHR()";
     bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
-    // Minimal validation for command buffer state
-    if (cb_state) {
-        skip |= PreCallValidateCmdPushDescriptorSetWithTemplateKHR(dev_data, cb_state);
-    }
-    lock.unlock();
+    skip |= ValidateCmd(device_data, cb_state, CMD_PUSHDESCRIPTORSETWITHTEMPLATEKHR, func_name);
 
-    if (!skip) {
-        dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
+    auto layout_data = GetPipelineLayout(device_data, layout);
+    auto dsl = GetDslFromPipelineLayout(layout_data, set);
+    const auto layout_u64 = HandleToUint64(layout);
+
+    // Validate the set index points to a push descriptor set and is in range
+    if (dsl) {
+        if (!dsl->IsPushDescriptor()) {
+            skip = log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
+                           layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00365",
+                           "%s: Set index %" PRIu32 " does not match push descriptor set layout index for VkPipelineLayout %s.",
+                           func_name, set, device_data->report_data->FormatHandle(layout_u64).c_str());
+        }
+    } else if (layout_data && (set >= layout_data->set_layouts.size())) {
+        skip = log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT,
+                       layout_u64, "VUID-vkCmdPushDescriptorSetKHR-set-00364",
+                       "%s: Set index %" PRIu32 " is outside of range for VkPipelineLayout %s (set < %" PRIu32 ").", func_name, set,
+                       device_data->report_data->FormatHandle(layout_u64).c_str(),
+                       static_cast<uint32_t>(layout_data->set_layouts.size()));
+    }
+
+    const auto template_state = GetDescriptorTemplateState(device_data, descriptorUpdateTemplate);
+    if (template_state) {
+        const auto &template_ci = template_state->create_info;
+        static const std::map<VkPipelineBindPoint, std::string> bind_errors = {
+            std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366"),
+            std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366"),
+            std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_NV,
+                           "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366")};
+        skip |= ValidatePipelineBindPoint(device_data, cb_state, template_ci.pipelineBindPoint, func_name, bind_errors);
+
+        if (template_ci.templateType != VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), kVUID_Core_PushDescriptorUpdate_TemplateType,
+                            "%s: descriptorUpdateTemplate %s was not created with flag "
+                            "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR.",
+                            func_name, device_data->report_data->FormatHandle(descriptorUpdateTemplate).c_str());
+        }
+        if (template_ci.set != set) {
+            skip |= log_msg(
+                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                HandleToUint64(cb_state->commandBuffer), kVUID_Core_PushDescriptorUpdate_Template_SetMismatched,
+                "%s: descriptorUpdateTemplate %s created with set %" PRIu32 " does not match command parameter set %" PRIu32 ".",
+                func_name, device_data->report_data->FormatHandle(descriptorUpdateTemplate).c_str(), template_ci.set, set);
+        }
+        if (!CompatForSet(set, layout_data, GetPipelineLayout(device_data, template_ci.pipelineLayout))) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                            HandleToUint64(cb_state->commandBuffer), kVUID_Core_PushDescriptorUpdate_Template_LayoutMismatched,
+                            "%s: descriptorUpdateTemplate %s created with pipelineLayout %s is incompatible with command parameter "
+                            "layout %s for set %" PRIu32,
+                            func_name, device_data->report_data->FormatHandle(descriptorUpdateTemplate).c_str(),
+                            device_data->report_data->FormatHandle(template_ci.pipelineLayout).c_str(),
+                            device_data->report_data->FormatHandle(layout).c_str(), set);
+        }
+    }
+
+    if (dsl && template_state) {
+        // Create an empty proxy in order to use the existing descriptor set update validation
+        cvdescriptorset::DescriptorSet proxy_ds(VK_NULL_HANDLE, VK_NULL_HANDLE, dsl, 0, device_data);
+        // Decode the template into a set of write updates
+        cvdescriptorset::DecodedTemplateUpdate decoded_template(device_data, VK_NULL_HANDLE, template_state, pData,
+                                                                dsl->GetDescriptorSetLayout());
+        // Validate the decoded update against the proxy_ds
+        skip |= proxy_ds.ValidatePushDescriptorsUpdate(device_data->report_data,
+                                                       static_cast<uint32_t>(decoded_template.desc_writes.size()),
+                                                       decoded_template.desc_writes.data(), func_name);
+    }
+
+    return skip;
+}
+
+void CoreChecks::PreCallRecordCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
+                                                                  VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                                  VkPipelineLayout layout, uint32_t set, const void *pData) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+
+    const auto template_state = GetDescriptorTemplateState(device_data, descriptorUpdateTemplate);
+    if (template_state) {
+        auto layout_data = GetPipelineLayout(device_data, layout);
+        auto dsl = GetDslFromPipelineLayout(layout_data, set);
+        const auto &template_ci = template_state->create_info;
+        if (dsl && !dsl->IsDestroyed()) {
+            // Decode the template into a set of write updates
+            cvdescriptorset::DecodedTemplateUpdate decoded_template(device_data, VK_NULL_HANDLE, template_state, pData,
+                                                                    dsl->GetDescriptorSetLayout());
+            RecordCmdPushDescriptorSetState(device_data, cb_state, template_ci.pipelineBindPoint, layout, set,
+                                            static_cast<uint32_t>(decoded_template.desc_writes.size()),
+                                            decoded_template.desc_writes.data());
+        }
     }
 }
 
-static void PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_layer_data *instanceData,
-                                                                     VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                     void *pProperties) {
-    unique_lock_t lock(global_lock);
-    auto physical_device_state = GetPhysicalDeviceState(instanceData, physicalDevice);
-
+void CoreChecks::RecordGetPhysicalDeviceDisplayPlanePropertiesState(instance_layer_data *instance_data,
+                                                                    VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                                    void *pProperties) {
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     if (*pPropertyCount) {
         if (physical_device_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHRState < QUERY_COUNT) {
             physical_device_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHRState = QUERY_COUNT;
@@ -14181,40 +13085,28 @@
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                          VkDisplayPlanePropertiesKHR *pProperties) {
-    VkResult result = VK_SUCCESS;
+void CoreChecks::PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                                          VkDisplayPlanePropertiesKHR *pProperties,
+                                                                          VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    result = instance_data->dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties);
-
-    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-        PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_data, physicalDevice, pPropertyCount, pProperties);
-    }
-
-    return result;
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
+    RecordGetPhysicalDeviceDisplayPlanePropertiesState(instance_data, physicalDevice, pPropertyCount, pProperties);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,
+void CoreChecks::PostCallRecordGetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,
                                                                            uint32_t *pPropertyCount,
-                                                                           VkDisplayPlaneProperties2KHR *pProperties) {
-    VkResult result = VK_SUCCESS;
+                                                                           VkDisplayPlaneProperties2KHR *pProperties,
+                                                                           VkResult result) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    result = instance_data->dispatch_table.GetPhysicalDeviceDisplayPlaneProperties2KHR(physicalDevice, pPropertyCount, pProperties);
-
-    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-        PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_data, physicalDevice, pPropertyCount, pProperties);
-    }
-
-    return result;
+    if ((VK_SUCCESS != result) && (VK_INCOMPLETE != result)) return;
+    RecordGetPhysicalDeviceDisplayPlanePropertiesState(instance_data, physicalDevice, pPropertyCount, pProperties);
 }
 
-static bool ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data *instance_data,
-                                                                    VkPhysicalDevice physicalDevice, uint32_t planeIndex,
-                                                                    const char *api_name) {
+bool CoreChecks::ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data *instance_data,
+                                                                         VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                         const char *api_name) {
     bool skip = false;
-    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+    auto physical_device_state = GetPhysicalDeviceState(physicalDevice);
     if (physical_device_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHRState == UNCALLED) {
         skip |=
             log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
@@ -14235,188 +13127,79 @@
     return skip;
 }
 
-static bool PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
-                                                               uint32_t planeIndex) {
+bool CoreChecks::PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                    uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
     bool skip = false;
-    lock_guard_t lock(global_lock);
     skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
                                                                     "vkGetDisplayPlaneSupportedDisplaysKHR");
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
-                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+bool CoreChecks::PreCallValidateGetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
+                                                               uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR *pCapabilities) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    bool skip = PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_data, physicalDevice, planeIndex);
-    if (!skip) {
-        result =
-            instance_data->dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
-    }
-    return result;
-}
-
-static bool PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
-                                                          uint32_t planeIndex) {
     bool skip = false;
-    lock_guard_t lock(global_lock);
     skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
                                                                     "vkGetDisplayPlaneCapabilitiesKHR");
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
-                                                              uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR *pCapabilities) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+bool CoreChecks::PreCallValidateGetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
+                                                                const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
+                                                                VkDisplayPlaneCapabilities2KHR *pCapabilities) {
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    bool skip = PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_data, physicalDevice, planeIndex);
-
-    if (!skip) {
-        result = instance_data->dispatch_table.GetDisplayPlaneCapabilitiesKHR(physicalDevice, mode, planeIndex, pCapabilities);
-    }
-
-    return result;
+    bool skip = false;
+    skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, pDisplayPlaneInfo->planeIndex,
+                                                                    "vkGetDisplayPlaneCapabilities2KHR");
+    return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
-                                                               const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
-                                                               VkDisplayPlaneCapabilities2KHR *pCapabilities) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    bool skip = PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_data, physicalDevice, pDisplayPlaneInfo->planeIndex);
-
-    if (!skip) {
-        result = instance_data->dispatch_table.GetDisplayPlaneCapabilities2KHR(physicalDevice, pDisplayPlaneInfo, pCapabilities);
-    }
-
-    return result;
-}
-
-static void PreCallRecordDebugMarkerSetObjectNameEXT(layer_data *dev_data, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
-    if (pNameInfo->pObjectName) {
-        dev_data->report_data->debugObjectNameMap->insert(
-            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->object, pNameInfo->pObjectName));
-    } else {
-        dev_data->report_data->debugObjectNameMap->erase(pNameInfo->object);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
-    unique_lock_t lock(global_lock);
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    PreCallRecordDebugMarkerSetObjectNameEXT(device_data, pNameInfo);
-    lock.unlock();
-    VkResult result = device_data->dispatch_table.DebugMarkerSetObjectNameEXT(device, pNameInfo);
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectTagEXT(VkDevice device, VkDebugMarkerObjectTagInfoEXT *pTagInfo) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = device_data->dispatch_table.DebugMarkerSetObjectTagEXT(device, pTagInfo);
-    return result;
-}
-
-static bool PreCallValidateCmdDebugMarkerBeginEXT(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    return ValidateCmd(dev_data, cb_state, CMD_DEBUGMARKERBEGINEXT, "vkCmdDebugMarkerBeginEXT()");
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT *pMarkerInfo) {
+bool CoreChecks::PreCallValidateCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer,
+                                                       const VkDebugMarkerMarkerInfoEXT *pMarkerInfo) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
-    // Minimal validation for command buffer state
-    if (cb_state) {
-        skip |= PreCallValidateCmdDebugMarkerBeginEXT(device_data, cb_state);
-    }
-    lock.unlock();
-    if (!skip) {
-        device_data->dispatch_table.CmdDebugMarkerBeginEXT(commandBuffer, pMarkerInfo);
-    }
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    return ValidateCmd(device_data, cb_state, CMD_DEBUGMARKERBEGINEXT, "vkCmdDebugMarkerBeginEXT()");
 }
 
-static bool PreCallValidateCmdDebugMarkerEndEXT(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    return ValidateCmd(dev_data, cb_state, CMD_DEBUGMARKERENDEXT, "vkCmdDebugMarkerEndEXT()");
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer) {
+bool CoreChecks::PreCallValidateCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
-    // Minimal validation for command buffer state
-    if (cb_state) {
-        skip |= PreCallValidateCmdDebugMarkerEndEXT(device_data, cb_state);
-    }
-    lock.unlock();
-    if (!skip) {
-        device_data->dispatch_table.CmdDebugMarkerEndEXT(commandBuffer);
-    }
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    assert(cb_state);
+    return ValidateCmd(device_data, cb_state, CMD_DEBUGMARKERENDEXT, "vkCmdDebugMarkerEndEXT()");
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDebugMarkerInsertEXT(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT *pMarkerInfo) {
+bool CoreChecks::PreCallValidateCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle,
+                                                          uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    device_data->dispatch_table.CmdDebugMarkerInsertEXT(commandBuffer, pMarkerInfo);
-}
-
-static bool PreCallValidateCmdSetDiscardRectangleEXT(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    return ValidateCmd(dev_data, cb_state, CMD_SETDISCARDRECTANGLEEXT, "vkCmdSetDiscardRectangleEXT()");
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle,
-                                                     uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     // Minimal validation for command buffer state
-    if (cb_state) {
-        skip |= PreCallValidateCmdSetDiscardRectangleEXT(dev_data, cb_state);
-    }
-    lock.unlock();
-
-    if (!skip) {
-        dev_data->dispatch_table.CmdSetDiscardRectangleEXT(commandBuffer, firstDiscardRectangle, discardRectangleCount,
-                                                           pDiscardRectangles);
-    }
+    return ValidateCmd(device_data, cb_state, CMD_SETDISCARDRECTANGLEEXT, "vkCmdSetDiscardRectangleEXT()");
 }
 
-static bool PreCallValidateCmdSetSampleLocationsEXT(layer_data *dev_data, GLOBAL_CB_NODE *cb_state) {
-    return ValidateCmd(dev_data, cb_state, CMD_SETSAMPLELOCATIONSEXT, "vkCmdSetSampleLocationsEXT()");
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,
-                                                    const VkSampleLocationsInfoEXT *pSampleLocationsInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    unique_lock_t lock(global_lock);
-    bool skip = false;
-    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
+bool CoreChecks::PreCallValidateCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,
+                                                         const VkSampleLocationsInfoEXT *pSampleLocationsInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
     // Minimal validation for command buffer state
-    if (cb_state) {
-        skip |= PreCallValidateCmdSetSampleLocationsEXT(dev_data, cb_state);
-    }
-    lock.unlock();
-
-    if (!skip) {
-        dev_data->dispatch_table.CmdSetSampleLocationsEXT(commandBuffer, pSampleLocationsInfo);
-    }
+    return ValidateCmd(device_data, cb_state, CMD_SETSAMPLELOCATIONSEXT, "vkCmdSetSampleLocationsEXT()");
 }
 
-static bool PreCallValidateCmdDrawIndirectCountKHR(layer_data *dev_data, VkCommandBuffer commandBuffer, VkBuffer buffer,
-                                                   VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset,
-                                                   uint32_t stride, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
-                                                   BUFFER_STATE **count_buffer_state, bool indexed, VkPipelineBindPoint bind_point,
-                                                   const char *caller) {
+bool CoreChecks::PreCallValidateCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                        VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                        uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = false;
     if (offset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndirectCountKHR-offset-03108",
                         "vkCmdDrawIndirectCountKHR() parameter, VkDeviceSize offset (0x%" PRIxLEAST64 "), is not a multiple of 4.",
                         offset);
     }
 
     if (countBufferOffset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndirectCountKHR-countBufferOffset-03109",
                         "vkCmdDrawIndirectCountKHR() parameter, VkDeviceSize countBufferOffset (0x%" PRIxLEAST64
                         "), is not a multiple of 4.",
@@ -14424,62 +13207,46 @@
     }
 
     if ((stride & 3) || stride < sizeof(VkDrawIndirectCommand)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndirectCountKHR-stride-03110",
                         "vkCmdDrawIndirectCountKHR() parameter, uint32_t stride (0x%" PRIxLEAST32
                         "), is not a multiple of 4 or smaller than sizeof (VkDrawIndirectCommand).",
                         stride);
     }
 
-    skip |= ValidateCmdDrawType(dev_data, commandBuffer, indexed, bind_point, CMD_DRAWINDIRECTCOUNTKHR, cb_state, caller,
-                                VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndirectCountKHR-commandBuffer-cmdpool",
-                                "VUID-vkCmdDrawIndirectCountKHR-renderpass", "VUID-vkCmdDrawIndirectCountKHR-None-03119",
-                                "VUID-vkCmdDrawIndirectCountKHR-None-03120");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    *count_buffer_state = GetBufferState(dev_data, countBuffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawIndirectCountKHR-buffer-03104");
-    skip |=
-        ValidateMemoryIsBoundToBuffer(dev_data, *count_buffer_state, caller, "VUID-vkCmdDrawIndirectCountKHR-countBuffer-03106");
+    skip |= ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWINDIRECTCOUNTKHR,
+                                "vkCmdDrawIndirectCountKHR()", VK_QUEUE_GRAPHICS_BIT,
+                                "VUID-vkCmdDrawIndirectCountKHR-commandBuffer-cmdpool", "VUID-vkCmdDrawIndirectCountKHR-renderpass",
+                                "VUID-vkCmdDrawIndirectCountKHR-None-03119", "VUID-vkCmdDrawIndirectCountKHR-None-03120");
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawIndirectCountKHR()",
+                                          "VUID-vkCmdDrawIndirectCountKHR-buffer-03104");
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, count_buffer_state, "vkCmdDrawIndirectCountKHR()",
+                                          "VUID-vkCmdDrawIndirectCountKHR-countBuffer-03106");
 
     return skip;
 }
 
-static void PreCallRecordCmdDrawIndirectCountKHR(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                                                 BUFFER_STATE *buffer_state, BUFFER_STATE *count_buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, count_buffer_state);
+void CoreChecks::PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                      VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                      uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
+    AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
+    AddCommandBufferBindingBuffer(device_data, cb_state, count_buffer_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                                   VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
-                                                   uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    BUFFER_STATE *count_buffer_state = nullptr;
-
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDrawIndirectCountKHR(dev_data, commandBuffer, buffer, offset, countBuffer, countBufferOffset,
-                                                       stride, &cb_state, &buffer_state, &count_buffer_state, false,
-                                                       VK_PIPELINE_BIND_POINT_GRAPHICS, "vkCmdDrawIndirectCountKHR()");
-
-    if (!skip) {
-        PreCallRecordCmdDrawIndirectCountKHR(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state, count_buffer_state);
-        lock.unlock();
-        dev_data->dispatch_table.CmdDrawIndirectCountKHR(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
-                                                         maxDrawCount, stride);
-    }
-}
-
-static bool PreCallValidateCmdDrawIndexedIndirectCountKHR(layer_data *dev_data, VkCommandBuffer commandBuffer, VkBuffer buffer,
-                                                          VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset,
-                                                          uint32_t stride, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
-                                                          BUFFER_STATE **count_buffer_state, bool indexed,
-                                                          VkPipelineBindPoint bind_point, const char *caller) {
+bool CoreChecks::PreCallValidateCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                               VkBuffer countBuffer, VkDeviceSize countBufferOffset,
+                                                               uint32_t maxDrawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = false;
     if (offset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndexedIndirectCountKHR-offset-03140",
                         "vkCmdDrawIndexedIndirectCountKHR() parameter, VkDeviceSize offset (0x%" PRIxLEAST64
                         "), is not a multiple of 4.",
@@ -14487,7 +13254,7 @@
     }
 
     if (countBufferOffset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndexedIndirectCountKHR-countBufferOffset-03141",
                         "vkCmdDrawIndexedIndirectCountKHR() parameter, VkDeviceSize countBufferOffset (0x%" PRIxLEAST64
                         "), is not a multiple of 4.",
@@ -14495,7 +13262,7 @@
     }
 
     if ((stride & 3) || stride < sizeof(VkDrawIndexedIndirectCommand)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawIndexedIndirectCountKHR-stride-03142",
                         "vkCmdDrawIndexedIndirectCountKHR() parameter, uint32_t stride (0x%" PRIxLEAST32
                         "), is not a multiple of 4 or smaller than sizeof (VkDrawIndexedIndirectCommand).",
@@ -14503,520 +13270,265 @@
     }
 
     skip |= ValidateCmdDrawType(
-        dev_data, commandBuffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECTCOUNTKHR, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
-        "VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-cmdpool", "VUID-vkCmdDrawIndexedIndirectCountKHR-renderpass",
-        "VUID-vkCmdDrawIndexedIndirectCountKHR-None-03151", "VUID-vkCmdDrawIndexedIndirectCountKHR-None-03152");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    *count_buffer_state = GetBufferState(dev_data, countBuffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03136");
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *count_buffer_state, caller,
+        device_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWINDEXEDINDIRECTCOUNTKHR,
+        "vkCmdDrawIndexedIndirectCountKHR()", VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-cmdpool",
+        "VUID-vkCmdDrawIndexedIndirectCountKHR-renderpass", "VUID-vkCmdDrawIndexedIndirectCountKHR-None-03151",
+        "VUID-vkCmdDrawIndexedIndirectCountKHR-None-03152");
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawIndexedIndirectCountKHR()",
+                                          "VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03136");
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, count_buffer_state, "vkCmdDrawIndexedIndirectCountKHR()",
                                           "VUID-vkCmdDrawIndexedIndirectCountKHR-countBuffer-03138");
     return skip;
 }
 
-static void PreCallRecordCmdDrawIndexedIndirectCountKHR(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
-                                                        VkPipelineBindPoint bind_point, BUFFER_STATE *buffer_state,
-                                                        BUFFER_STATE *count_buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
-    AddCommandBufferBindingBuffer(dev_data, cb_state, count_buffer_state);
+void CoreChecks::PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                             VkBuffer countBuffer, VkDeviceSize countBufferOffset,
+                                                             uint32_t maxDrawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
+    AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
+    AddCommandBufferBindingBuffer(device_data, cb_state, count_buffer_state);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                                          VkBuffer countBuffer, VkDeviceSize countBufferOffset,
-                                                          uint32_t maxDrawCount, uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    BUFFER_STATE *count_buffer_state = nullptr;
-    unique_lock_t lock(global_lock);
-    bool skip = PreCallValidateCmdDrawIndexedIndirectCountKHR(
-        dev_data, commandBuffer, buffer, offset, countBuffer, countBufferOffset, stride, &cb_state, &buffer_state,
-        &count_buffer_state, true, VK_PIPELINE_BIND_POINT_GRAPHICS, "vkCmdDrawIndexedIndirectCountKHR()");
-
-    if (!skip) {
-        PreCallRecordCmdDrawIndexedIndirectCountKHR(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state,
-                                                    count_buffer_state);
-        lock.unlock();
-        dev_data->dispatch_table.CmdDrawIndexedIndirectCountKHR(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
-                                                                maxDrawCount, stride);
-    }
-}
-
-static bool PreCallValidateCmdDrawMeshTasksNV(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
-                                              VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
-    bool skip =
-        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWMESHTASKSNV, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
-                            "VUID-vkCmdDrawMeshTasksNV-commandBuffer-cmdpool", "VUID-vkCmdDrawMeshTasksNV-renderpass",
-                            "VUID-vkCmdDrawMeshTasksNV-None-02125", "VUID-vkCmdDrawMeshTasksNV-None-02126");
-
+bool CoreChecks::PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWMESHTASKSNV,
+                                    "vkCmdDrawMeshTasksNV()", VK_QUEUE_GRAPHICS_BIT,
+                                    "VUID-vkCmdDrawMeshTasksNV-commandBuffer-cmdpool", "VUID-vkCmdDrawMeshTasksNV-renderpass",
+                                    "VUID-vkCmdDrawMeshTasksNV-None-02125", "VUID-vkCmdDrawMeshTasksNV-None-02126");
     return skip;
 }
 
-static void PreCallRecordCmdDrawMeshTasksNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    bool skip = false;
-
-    unique_lock_t lock(global_lock);
-    skip |= PreCallValidateCmdDrawMeshTasksNV(dev_data, commandBuffer, /* indexed */ false, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                              &cb_state, "vkCmdDrawMeshTasksNV()");
-
-    if (!skip) {
-        PreCallRecordCmdDrawMeshTasksNV(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
-        lock.unlock();
-        dev_data->dispatch_table.CmdDrawMeshTasksNV(commandBuffer, taskCount, firstTask);
-    }
-}
-
-static bool PreCallValidateCmdDrawMeshTasksIndirectNV(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer,
-                                                      bool indexed, VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
-                                                      BUFFER_STATE **buffer_state, const char *caller) {
-    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWMESHTASKSINDIRECTNV, cb_state, caller,
-                                    VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdDrawMeshTasksIndirectNV-commandBuffer-cmdpool",
+bool CoreChecks::PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                           uint32_t drawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip = ValidateCmdDrawType(device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWMESHTASKSINDIRECTNV,
+                                    "vkCmdDrawMeshTasksIndirectNV()", VK_QUEUE_GRAPHICS_BIT,
+                                    "VUID-vkCmdDrawMeshTasksIndirectNV-commandBuffer-cmdpool",
                                     "VUID-vkCmdDrawMeshTasksIndirectNV-renderpass", "VUID-vkCmdDrawMeshTasksIndirectNV-None-02154",
                                     "VUID-vkCmdDrawMeshTasksIndirectNV-None-02155");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawMeshTasksIndirectNV-buffer-02143");
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawMeshTasksIndirectNV()",
+                                          "VUID-vkCmdDrawMeshTasksIndirectNV-buffer-02143");
 
     return skip;
 }
 
-static void PreCallRecordCmdDrawMeshTasksIndirectNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
-                                                    BUFFER_STATE *buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                         uint32_t drawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
     if (buffer_state) {
-        AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
+        AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                                      uint32_t drawCount, uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    bool skip = false;
-
-    unique_lock_t lock(global_lock);
-    skip |= PreCallValidateCmdDrawMeshTasksIndirectNV(dev_data, commandBuffer, buffer, /* indexed */ false,
-                                                      VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, &buffer_state,
-                                                      "vkCmdDrawMeshTasksIndirectNV()");
-
-    if (!skip) {
-        PreCallRecordCmdDrawMeshTasksIndirectNV(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
-        lock.unlock();
-        dev_data->dispatch_table.CmdDrawMeshTasksIndirectNV(commandBuffer, buffer, offset, drawCount, stride);
-    }
-}
-
-static bool PreCallValidateCmdDrawMeshTasksIndirectCountNV(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer,
-                                                           VkBuffer count_buffer, bool indexed, VkPipelineBindPoint bind_point,
-                                                           GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
-                                                           BUFFER_STATE **count_buffer_state, const char *caller) {
+bool CoreChecks::PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                                VkBuffer countBuffer, VkDeviceSize countBufferOffset,
+                                                                uint32_t maxDrawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     bool skip = ValidateCmdDrawType(
-        dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWMESHTASKSINDIRECTCOUNTNV, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
+        device_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, CMD_DRAWMESHTASKSINDIRECTCOUNTNV,
+        "vkCmdDrawMeshTasksIndirectCountNV()", VK_QUEUE_GRAPHICS_BIT,
         "VUID-vkCmdDrawMeshTasksIndirectCountNV-commandBuffer-cmdpool", "VUID-vkCmdDrawMeshTasksIndirectCountNV-renderpass",
         "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-02189", "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-02190");
-    *buffer_state = GetBufferState(dev_data, buffer);
-    *count_buffer_state = GetBufferState(dev_data, count_buffer);
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, "VUID-vkCmdDrawMeshTasksIndirectCountNV-buffer-02176");
-    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *count_buffer_state, caller,
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdDrawMeshTasksIndirectCountNV()",
+                                          "VUID-vkCmdDrawMeshTasksIndirectCountNV-buffer-02176");
+    skip |= ValidateMemoryIsBoundToBuffer(device_data, count_buffer_state, "vkCmdDrawMeshTasksIndirectCountNV()",
                                           "VUID-vkCmdDrawMeshTasksIndirectCountNV-countBuffer-02178");
 
     return skip;
 }
 
-static void PreCallRecordCmdDrawMeshTasksIndirectCountNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
-                                                         VkPipelineBindPoint bind_point, BUFFER_STATE *buffer_state,
-                                                         BUFFER_STATE *count_buffer_state) {
-    UpdateStateCmdDrawType(dev_data, cb_state, bind_point);
+void CoreChecks::PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                              VkBuffer countBuffer, VkDeviceSize countBufferOffset,
+                                                              uint32_t maxDrawCount, uint32_t stride) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    GLOBAL_CB_NODE *cb_state = GetCBNode(commandBuffer);
+    BUFFER_STATE *buffer_state = GetBufferState(buffer);
+    BUFFER_STATE *count_buffer_state = GetBufferState(countBuffer);
+    UpdateStateCmdDrawType(device_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
     if (buffer_state) {
-        AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
+        AddCommandBufferBindingBuffer(device_data, cb_state, buffer_state);
     }
     if (count_buffer_state) {
-        AddCommandBufferBindingBuffer(dev_data, cb_state, count_buffer_state);
+        AddCommandBufferBindingBuffer(device_data, cb_state, count_buffer_state);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
-                                                           VkBuffer countBuffer, VkDeviceSize countBufferOffset,
-                                                           uint32_t maxDrawCount, uint32_t stride) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    GLOBAL_CB_NODE *cb_state = nullptr;
-    BUFFER_STATE *buffer_state = nullptr;
-    BUFFER_STATE *count_buffer_state = nullptr;
+bool CoreChecks::ValidateCreateSamplerYcbcrConversion(const layer_data *device_data, const char *func_name,
+                                                      const VkSamplerYcbcrConversionCreateInfo *create_info) {
+    bool skip = false;
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        skip |= ValidateCreateSamplerYcbcrConversionANDROID(device_data, create_info);
+    } else {  // Not android hardware buffer
+        if (VK_FORMAT_UNDEFINED == create_info->format) {
+            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                            VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, 0,
+                            "VUID-VkSamplerYcbcrConversionCreateInfo-format-01649",
+                            "%s: CreateInfo format type is VK_FORMAT_UNDEFINED.", func_name);
+        }
+    }
+    return skip;
+}
+
+bool CoreChecks::PreCallValidateCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
+                                                             const VkAllocationCallbacks *pAllocator,
+                                                             VkSamplerYcbcrConversion *pYcbcrConversion) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateCreateSamplerYcbcrConversion(device_data, "vkCreateSamplerYcbcrConversion()", pCreateInfo);
+}
+
+bool CoreChecks::PreCallValidateCreateSamplerYcbcrConversionKHR(VkDevice device,
+                                                                const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
+                                                                const VkAllocationCallbacks *pAllocator,
+                                                                VkSamplerYcbcrConversion *pYcbcrConversion) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    return ValidateCreateSamplerYcbcrConversion(device_data, "vkCreateSamplerYcbcrConversionKHR()", pCreateInfo);
+}
+
+void CoreChecks::RecordCreateSamplerYcbcrConversionState(layer_data *device_data,
+                                                         const VkSamplerYcbcrConversionCreateInfo *create_info,
+                                                         VkSamplerYcbcrConversion ycbcr_conversion) {
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        RecordCreateSamplerYcbcrConversionANDROID(device_data, create_info, ycbcr_conversion);
+    }
+}
+
+void CoreChecks::PostCallRecordCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkSamplerYcbcrConversion *pYcbcrConversion, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordCreateSamplerYcbcrConversionState(device_data, pCreateInfo, *pYcbcrConversion);
+}
+
+void CoreChecks::PostCallRecordCreateSamplerYcbcrConversionKHR(VkDevice device,
+                                                               const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
+                                                               const VkAllocationCallbacks *pAllocator,
+                                                               VkSamplerYcbcrConversion *pYcbcrConversion, VkResult result) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (VK_SUCCESS != result) return;
+    RecordCreateSamplerYcbcrConversionState(device_data, pCreateInfo, *pYcbcrConversion);
+}
+
+void CoreChecks::PostCallRecordDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion,
+                                                             const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!ycbcrConversion) return;
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        RecordDestroySamplerYcbcrConversionANDROID(device_data, ycbcrConversion);
+    }
+}
+
+void CoreChecks::PostCallRecordDestroySamplerYcbcrConversionKHR(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion,
+                                                                const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!ycbcrConversion) return;
+    if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
+        RecordDestroySamplerYcbcrConversionANDROID(device_data, ycbcrConversion);
+    }
+}
+
+bool CoreChecks::PreCallValidateGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfoEXT *pInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     bool skip = false;
 
-    unique_lock_t lock(global_lock);
-    skip |= PreCallValidateCmdDrawMeshTasksIndirectCountNV(dev_data, commandBuffer, buffer, countBuffer, /* indexed */ false,
-                                                           VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, &buffer_state,
-                                                           &count_buffer_state, "vkCmdDrawMeshTasksIndirectCountNV()");
+    if (!GetEnabledFeatures()->buffer_address.bufferDeviceAddress) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                        HandleToUint64(pInfo->buffer), "VUID-vkGetBufferDeviceAddressEXT-None-02598",
+                        "The bufferDeviceAddress feature must: be enabled.");
+    }
 
-    if (!skip) {
-        PreCallRecordCmdDrawMeshTasksIndirectCountNV(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state,
-                                                     count_buffer_state);
-        lock.unlock();
-        dev_data->dispatch_table.CmdDrawMeshTasksIndirectCountNV(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
-                                                                 maxDrawCount, stride);
+    if (device_data->physical_device_count > 1 && !GetEnabledFeatures()->buffer_address.bufferDeviceAddressMultiDevice) {
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
+                        HandleToUint64(pInfo->buffer), "VUID-vkGetBufferDeviceAddressEXT-device-02599",
+                        "If device was created with multiple physical devices, then the "
+                        "bufferDeviceAddressMultiDevice feature must: be enabled.");
+    }
+
+    auto buffer_state = GetBufferState(pInfo->buffer);
+    if (buffer_state) {
+        if (!(buffer_state->createInfo.flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT)) {
+            skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkGetBufferDeviceAddressEXT()",
+                                                  "VUID-VkBufferDeviceAddressInfoEXT-buffer-02600");
+        }
+
+        skip |= ValidateBufferUsageFlags(device_data, buffer_state, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT, true,
+                                         "VUID-VkBufferDeviceAddressInfoEXT-buffer-02601", "vkGetBufferDeviceAddressEXT()",
+                                         "VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT");
+    }
+
+    return skip;
+}
+
+void CoreChecks::PreCallRecordGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
+                                                          VkPhysicalDeviceProperties *pPhysicalDeviceProperties) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    if (GetEnables()->gpu_validation && GetEnables()->gpu_validation_reserve_binding_slot) {
+        if (pPhysicalDeviceProperties->limits.maxBoundDescriptorSets > 1) {
+            pPhysicalDeviceProperties->limits.maxBoundDescriptorSets -= 1;
+        } else {
+            log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                    HandleToUint64(physicalDevice), "UNASSIGNED-GPU-Assisted Validation Setup Error.",
+                    "Unable to reserve descriptor binding slot on a device with only one slot.");
+        }
     }
 }
 
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName);
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName);
+VkResult CoreChecks::CoreLayerCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo,
+                                                       const VkAllocationCallbacks *pAllocator,
+                                                       VkValidationCacheEXT *pValidationCache) {
+    *pValidationCache = ValidationCache::Create(pCreateInfo);
+    return *pValidationCache ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
+}
 
-// Map of all APIs to be intercepted by this layer
-static const std::unordered_map<std::string, void *> name_to_funcptr_map = {
-    {"vkGetInstanceProcAddr", (void *)GetInstanceProcAddr},
-    {"vk_layerGetPhysicalDeviceProcAddr", (void *)GetPhysicalDeviceProcAddr},
-    {"vkGetDeviceProcAddr", (void *)GetDeviceProcAddr},
-    {"vkCreateInstance", (void *)CreateInstance},
-    {"vkCreateDevice", (void *)CreateDevice},
-    {"vkEnumeratePhysicalDevices", (void *)EnumeratePhysicalDevices},
-    {"vkGetPhysicalDeviceQueueFamilyProperties", (void *)GetPhysicalDeviceQueueFamilyProperties},
-    {"vkDestroyInstance", (void *)DestroyInstance},
-    {"vkEnumerateInstanceLayerProperties", (void *)EnumerateInstanceLayerProperties},
-    {"vkEnumerateDeviceLayerProperties", (void *)EnumerateDeviceLayerProperties},
-    {"vkEnumerateInstanceExtensionProperties", (void *)EnumerateInstanceExtensionProperties},
-    {"vkEnumerateDeviceExtensionProperties", (void *)EnumerateDeviceExtensionProperties},
-    {"vkCreateDescriptorUpdateTemplate", (void *)CreateDescriptorUpdateTemplate},
-    {"vkCreateDescriptorUpdateTemplateKHR", (void *)CreateDescriptorUpdateTemplateKHR},
-    {"vkDestroyDescriptorUpdateTemplate", (void *)DestroyDescriptorUpdateTemplate},
-    {"vkDestroyDescriptorUpdateTemplateKHR", (void *)DestroyDescriptorUpdateTemplateKHR},
-    {"vkUpdateDescriptorSetWithTemplate", (void *)UpdateDescriptorSetWithTemplate},
-    {"vkUpdateDescriptorSetWithTemplateKHR", (void *)UpdateDescriptorSetWithTemplateKHR},
-    {"vkCmdPushDescriptorSetWithTemplateKHR", (void *)CmdPushDescriptorSetWithTemplateKHR},
-    {"vkCmdPushDescriptorSetKHR", (void *)CmdPushDescriptorSetKHR},
-    {"vkCreateSwapchainKHR", (void *)CreateSwapchainKHR},
-    {"vkDestroySwapchainKHR", (void *)DestroySwapchainKHR},
-    {"vkGetSwapchainImagesKHR", (void *)GetSwapchainImagesKHR},
-    {"vkAcquireNextImageKHR", (void *)AcquireNextImageKHR},
-    {"vkAcquireNextImage2KHR", (void *)AcquireNextImage2KHR},
-    {"vkQueuePresentKHR", (void *)QueuePresentKHR},
-    {"vkQueueSubmit", (void *)QueueSubmit},
-    {"vkWaitForFences", (void *)WaitForFences},
-    {"vkGetFenceStatus", (void *)GetFenceStatus},
-    {"vkQueueWaitIdle", (void *)QueueWaitIdle},
-    {"vkDeviceWaitIdle", (void *)DeviceWaitIdle},
-    {"vkGetDeviceQueue", (void *)GetDeviceQueue},
-    {"vkGetDeviceQueue2", (void *)GetDeviceQueue2},
-    {"vkDestroyDevice", (void *)DestroyDevice},
-    {"vkDestroyFence", (void *)DestroyFence},
-    {"vkResetFences", (void *)ResetFences},
-    {"vkDestroySemaphore", (void *)DestroySemaphore},
-    {"vkDestroyEvent", (void *)DestroyEvent},
-    {"vkDestroyQueryPool", (void *)DestroyQueryPool},
-    {"vkDestroyBuffer", (void *)DestroyBuffer},
-    {"vkDestroyBufferView", (void *)DestroyBufferView},
-    {"vkDestroyImage", (void *)DestroyImage},
-    {"vkDestroyImageView", (void *)DestroyImageView},
-    {"vkDestroyShaderModule", (void *)DestroyShaderModule},
-    {"vkDestroyPipeline", (void *)DestroyPipeline},
-    {"vkDestroyPipelineLayout", (void *)DestroyPipelineLayout},
-    {"vkDestroySampler", (void *)DestroySampler},
-    {"vkDestroyDescriptorSetLayout", (void *)DestroyDescriptorSetLayout},
-    {"vkDestroyDescriptorPool", (void *)DestroyDescriptorPool},
-    {"vkDestroyFramebuffer", (void *)DestroyFramebuffer},
-    {"vkDestroyRenderPass", (void *)DestroyRenderPass},
-    {"vkCreateBuffer", (void *)CreateBuffer},
-    {"vkCreateBufferView", (void *)CreateBufferView},
-    {"vkCreateImage", (void *)CreateImage},
-    {"vkCreateImageView", (void *)CreateImageView},
-    {"vkCreateFence", (void *)CreateFence},
-    {"vkCreatePipelineCache", (void *)CreatePipelineCache},
-    {"vkDestroyPipelineCache", (void *)DestroyPipelineCache},
-    {"vkGetPipelineCacheData", (void *)GetPipelineCacheData},
-    {"vkMergePipelineCaches", (void *)MergePipelineCaches},
-    {"vkCreateGraphicsPipelines", (void *)CreateGraphicsPipelines},
-    {"vkCreateComputePipelines", (void *)CreateComputePipelines},
-    {"vkCreateSampler", (void *)CreateSampler},
-    {"vkCreateDescriptorSetLayout", (void *)CreateDescriptorSetLayout},
-    {"vkCreatePipelineLayout", (void *)CreatePipelineLayout},
-    {"vkCreateDescriptorPool", (void *)CreateDescriptorPool},
-    {"vkResetDescriptorPool", (void *)ResetDescriptorPool},
-    {"vkAllocateDescriptorSets", (void *)AllocateDescriptorSets},
-    {"vkFreeDescriptorSets", (void *)FreeDescriptorSets},
-    {"vkUpdateDescriptorSets", (void *)UpdateDescriptorSets},
-    {"vkCreateCommandPool", (void *)CreateCommandPool},
-    {"vkDestroyCommandPool", (void *)DestroyCommandPool},
-    {"vkResetCommandPool", (void *)ResetCommandPool},
-    {"vkCreateQueryPool", (void *)CreateQueryPool},
-    {"vkAllocateCommandBuffers", (void *)AllocateCommandBuffers},
-    {"vkFreeCommandBuffers", (void *)FreeCommandBuffers},
-    {"vkBeginCommandBuffer", (void *)BeginCommandBuffer},
-    {"vkEndCommandBuffer", (void *)EndCommandBuffer},
-    {"vkResetCommandBuffer", (void *)ResetCommandBuffer},
-    {"vkCmdBindPipeline", (void *)CmdBindPipeline},
-    {"vkCmdSetViewport", (void *)CmdSetViewport},
-    {"vkCmdSetScissor", (void *)CmdSetScissor},
-    {"vkCmdSetLineWidth", (void *)CmdSetLineWidth},
-    {"vkCmdSetDepthBias", (void *)CmdSetDepthBias},
-    {"vkCmdSetBlendConstants", (void *)CmdSetBlendConstants},
-    {"vkCmdSetDepthBounds", (void *)CmdSetDepthBounds},
-    {"vkCmdSetStencilCompareMask", (void *)CmdSetStencilCompareMask},
-    {"vkCmdSetStencilWriteMask", (void *)CmdSetStencilWriteMask},
-    {"vkCmdSetStencilReference", (void *)CmdSetStencilReference},
-    {"vkCmdBindDescriptorSets", (void *)CmdBindDescriptorSets},
-    {"vkCmdBindVertexBuffers", (void *)CmdBindVertexBuffers},
-    {"vkCmdBindIndexBuffer", (void *)CmdBindIndexBuffer},
-    {"vkCmdDraw", (void *)CmdDraw},
-    {"vkCmdDrawIndexed", (void *)CmdDrawIndexed},
-    {"vkCmdDrawIndirect", (void *)CmdDrawIndirect},
-    {"vkCmdDrawIndexedIndirect", (void *)CmdDrawIndexedIndirect},
-    {"vkCmdDispatch", (void *)CmdDispatch},
-    {"vkCmdDispatchIndirect", (void *)CmdDispatchIndirect},
-    {"vkCmdCopyBuffer", (void *)CmdCopyBuffer},
-    {"vkCmdCopyImage", (void *)CmdCopyImage},
-    {"vkCmdBlitImage", (void *)CmdBlitImage},
-    {"vkCmdCopyBufferToImage", (void *)CmdCopyBufferToImage},
-    {"vkCmdCopyImageToBuffer", (void *)CmdCopyImageToBuffer},
-    {"vkCmdUpdateBuffer", (void *)CmdUpdateBuffer},
-    {"vkCmdFillBuffer", (void *)CmdFillBuffer},
-    {"vkCmdClearColorImage", (void *)CmdClearColorImage},
-    {"vkCmdClearDepthStencilImage", (void *)CmdClearDepthStencilImage},
-    {"vkCmdClearAttachments", (void *)CmdClearAttachments},
-    {"vkCmdResolveImage", (void *)CmdResolveImage},
-    {"vkGetImageSubresourceLayout", (void *)GetImageSubresourceLayout},
-    {"vkCmdSetEvent", (void *)CmdSetEvent},
-    {"vkCmdResetEvent", (void *)CmdResetEvent},
-    {"vkCmdWaitEvents", (void *)CmdWaitEvents},
-    {"vkCmdPipelineBarrier", (void *)CmdPipelineBarrier},
-    {"vkCmdBeginQuery", (void *)CmdBeginQuery},
-    {"vkCmdEndQuery", (void *)CmdEndQuery},
-    {"vkCmdResetQueryPool", (void *)CmdResetQueryPool},
-    {"vkCmdCopyQueryPoolResults", (void *)CmdCopyQueryPoolResults},
-    {"vkCmdPushConstants", (void *)CmdPushConstants},
-    {"vkCmdWriteTimestamp", (void *)CmdWriteTimestamp},
-    {"vkCreateFramebuffer", (void *)CreateFramebuffer},
-    {"vkCreateShaderModule", (void *)CreateShaderModule},
-    {"vkCreateRenderPass", (void *)CreateRenderPass},
-    {"vkCmdBeginRenderPass", (void *)CmdBeginRenderPass},
-    {"vkCmdNextSubpass", (void *)CmdNextSubpass},
-    {"vkCmdEndRenderPass", (void *)CmdEndRenderPass},
-    {"vkCmdExecuteCommands", (void *)CmdExecuteCommands},
-    {"vkCmdDebugMarkerBeginEXT", (void *)CmdDebugMarkerBeginEXT},
-    {"vkCmdDebugMarkerEndEXT", (void *)CmdDebugMarkerEndEXT},
-    {"vkCmdDebugMarkerInsertEXT", (void *)CmdDebugMarkerInsertEXT},
-    {"vkDebugMarkerSetObjectNameEXT", (void *)DebugMarkerSetObjectNameEXT},
-    {"vkDebugMarkerSetObjectTagEXT", (void *)DebugMarkerSetObjectTagEXT},
-    {"vkSetEvent", (void *)SetEvent},
-    {"vkMapMemory", (void *)MapMemory},
-    {"vkUnmapMemory", (void *)UnmapMemory},
-    {"vkFlushMappedMemoryRanges", (void *)FlushMappedMemoryRanges},
-    {"vkInvalidateMappedMemoryRanges", (void *)InvalidateMappedMemoryRanges},
-    {"vkAllocateMemory", (void *)AllocateMemory},
-    {"vkFreeMemory", (void *)FreeMemory},
-    {"vkBindBufferMemory", (void *)BindBufferMemory},
-    {"vkBindBufferMemory2", (void *)BindBufferMemory2},
-    {"vkBindBufferMemory2KHR", (void *)BindBufferMemory2KHR},
-    {"vkGetBufferMemoryRequirements", (void *)GetBufferMemoryRequirements},
-    {"vkGetBufferMemoryRequirements2", (void *)GetBufferMemoryRequirements2},
-    {"vkGetBufferMemoryRequirements2KHR", (void *)GetBufferMemoryRequirements2KHR},
-    {"vkGetImageMemoryRequirements", (void *)GetImageMemoryRequirements},
-    {"vkGetImageMemoryRequirements2", (void *)GetImageMemoryRequirements2},
-    {"vkGetImageMemoryRequirements2KHR", (void *)GetImageMemoryRequirements2KHR},
-    {"vkGetImageSparseMemoryRequirements", (void *)GetImageSparseMemoryRequirements},
-    {"vkGetImageSparseMemoryRequirements2", (void *)GetImageSparseMemoryRequirements2},
-    {"vkGetImageSparseMemoryRequirements2KHR", (void *)GetImageSparseMemoryRequirements2KHR},
-    {"vkGetPhysicalDeviceSparseImageFormatProperties", (void *)GetPhysicalDeviceSparseImageFormatProperties},
-    {"vkGetPhysicalDeviceSparseImageFormatProperties2", (void *)GetPhysicalDeviceSparseImageFormatProperties2},
-    {"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", (void *)GetPhysicalDeviceSparseImageFormatProperties2KHR},
-    {"vkGetQueryPoolResults", (void *)GetQueryPoolResults},
-    {"vkBindImageMemory", (void *)BindImageMemory},
-    {"vkBindImageMemory2", (void *)BindImageMemory2},
-    {"vkBindImageMemory2KHR", (void *)BindImageMemory2KHR},
-    {"vkQueueBindSparse", (void *)QueueBindSparse},
-    {"vkCreateSemaphore", (void *)CreateSemaphore},
-    {"vkCreateEvent", (void *)CreateEvent},
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-    {"vkCreateAndroidSurfaceKHR", (void *)CreateAndroidSurfaceKHR},
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
-    {"vkCreateWaylandSurfaceKHR", (void *)CreateWaylandSurfaceKHR},
-    {"vkGetPhysicalDeviceWaylandPresentationSupportKHR", (void *)GetPhysicalDeviceWaylandPresentationSupportKHR},
-#endif
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-    {"vkCreateWin32SurfaceKHR", (void *)CreateWin32SurfaceKHR},
-    {"vkGetPhysicalDeviceWin32PresentationSupportKHR", (void *)GetPhysicalDeviceWin32PresentationSupportKHR},
-    {"vkImportSemaphoreWin32HandleKHR", (void *)ImportSemaphoreWin32HandleKHR},
-    {"vkGetSemaphoreWin32HandleKHR", (void *)GetSemaphoreWin32HandleKHR},
-    {"vkImportFenceWin32HandleKHR", (void *)ImportFenceWin32HandleKHR},
-    {"vkGetFenceWin32HandleKHR", (void *)GetFenceWin32HandleKHR},
-#endif
-#ifdef VK_USE_PLATFORM_XCB_KHR
-    {"vkCreateXcbSurfaceKHR", (void *)CreateXcbSurfaceKHR},
-    {"vkGetPhysicalDeviceXcbPresentationSupportKHR", (void *)GetPhysicalDeviceXcbPresentationSupportKHR},
-#endif
-#ifdef VK_USE_PLATFORM_XLIB_KHR
-    {"vkCreateXlibSurfaceKHR", (void *)CreateXlibSurfaceKHR},
-    {"vkGetPhysicalDeviceXlibPresentationSupportKHR", (void *)GetPhysicalDeviceXlibPresentationSupportKHR},
-#endif
-#ifdef VK_USE_PLATFORM_IOS_MVK
-    {"vkCreateIOSSurfaceMVK", (void *)CreateIOSSurfaceMVK},
-#endif
-#ifdef VK_USE_PLATFORM_MACOS_MVK
-    {"vkCreateMacOSSurfaceMVK", (void *)CreateMacOSSurfaceMVK},
-#endif
-    {"vkCreateDisplayPlaneSurfaceKHR", (void *)CreateDisplayPlaneSurfaceKHR},
-    {"vkDestroySurfaceKHR", (void *)DestroySurfaceKHR},
-    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", (void *)GetPhysicalDeviceSurfaceCapabilitiesKHR},
-    {"vkGetPhysicalDeviceSurfaceCapabilities2KHR", (void *)GetPhysicalDeviceSurfaceCapabilities2KHR},
-    {"vkGetPhysicalDeviceSurfaceCapabilities2EXT", (void *)GetPhysicalDeviceSurfaceCapabilities2EXT},
-    {"vkGetPhysicalDeviceSurfaceSupportKHR", (void *)GetPhysicalDeviceSurfaceSupportKHR},
-    {"vkGetPhysicalDeviceSurfacePresentModesKHR", (void *)GetPhysicalDeviceSurfacePresentModesKHR},
-    {"vkGetPhysicalDeviceSurfaceFormatsKHR", (void *)GetPhysicalDeviceSurfaceFormatsKHR},
-    {"vkGetPhysicalDeviceSurfaceFormats2KHR", (void *)GetPhysicalDeviceSurfaceFormats2KHR},
-    {"vkGetPhysicalDeviceQueueFamilyProperties2", (void *)GetPhysicalDeviceQueueFamilyProperties2},
-    {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", (void *)GetPhysicalDeviceQueueFamilyProperties2KHR},
-    {"vkEnumeratePhysicalDeviceGroups", (void *)EnumeratePhysicalDeviceGroups},
-    {"vkEnumeratePhysicalDeviceGroupsKHR", (void *)EnumeratePhysicalDeviceGroupsKHR},
-    {"vkCreateDebugReportCallbackEXT", (void *)CreateDebugReportCallbackEXT},
-    {"vkDestroyDebugReportCallbackEXT", (void *)DestroyDebugReportCallbackEXT},
-    {"vkDebugReportMessageEXT", (void *)DebugReportMessageEXT},
-    {"vkGetPhysicalDeviceDisplayPlanePropertiesKHR", (void *)GetPhysicalDeviceDisplayPlanePropertiesKHR},
-    {"vkGetPhysicalDeviceDisplayPlaneProperties2KHR", (void *)GetPhysicalDeviceDisplayPlaneProperties2KHR},
-    {"vkGetDisplayPlaneSupportedDisplaysKHR", (void *)GetDisplayPlaneSupportedDisplaysKHR},
-    {"vkGetDisplayPlaneCapabilitiesKHR", (void *)GetDisplayPlaneCapabilitiesKHR},
-    {"vkGetDisplayPlaneCapabilities2KHR", (void *)GetDisplayPlaneCapabilities2KHR},
-    {"vkImportSemaphoreFdKHR", (void *)ImportSemaphoreFdKHR},
-    {"vkGetSemaphoreFdKHR", (void *)GetSemaphoreFdKHR},
-    {"vkImportFenceFdKHR", (void *)ImportFenceFdKHR},
-    {"vkGetFenceFdKHR", (void *)GetFenceFdKHR},
-    {"vkCreateValidationCacheEXT", (void *)CreateValidationCacheEXT},
-    {"vkDestroyValidationCacheEXT", (void *)DestroyValidationCacheEXT},
-    {"vkGetValidationCacheDataEXT", (void *)GetValidationCacheDataEXT},
-    {"vkMergeValidationCachesEXT", (void *)MergeValidationCachesEXT},
-    {"vkCmdSetDiscardRectangleEXT", (void *)CmdSetDiscardRectangleEXT},
-    {"vkCmdSetSampleLocationsEXT", (void *)CmdSetSampleLocationsEXT},
-    {"vkSetDebugUtilsObjectNameEXT", (void *)SetDebugUtilsObjectNameEXT},
-    {"vkSetDebugUtilsObjectTagEXT", (void *)SetDebugUtilsObjectTagEXT},
-    {"vkQueueBeginDebugUtilsLabelEXT", (void *)QueueBeginDebugUtilsLabelEXT},
-    {"vkQueueEndDebugUtilsLabelEXT", (void *)QueueEndDebugUtilsLabelEXT},
-    {"vkQueueInsertDebugUtilsLabelEXT", (void *)QueueInsertDebugUtilsLabelEXT},
-    {"vkCmdBeginDebugUtilsLabelEXT", (void *)CmdBeginDebugUtilsLabelEXT},
-    {"vkCmdEndDebugUtilsLabelEXT", (void *)CmdEndDebugUtilsLabelEXT},
-    {"vkCmdInsertDebugUtilsLabelEXT", (void *)CmdInsertDebugUtilsLabelEXT},
-    {"vkCreateDebugUtilsMessengerEXT", (void *)CreateDebugUtilsMessengerEXT},
-    {"vkDestroyDebugUtilsMessengerEXT", (void *)DestroyDebugUtilsMessengerEXT},
-    {"vkSubmitDebugUtilsMessageEXT", (void *)SubmitDebugUtilsMessageEXT},
-    {"vkCmdDrawIndirectCountKHR", (void *)CmdDrawIndirectCountKHR},
-    {"vkCmdDrawIndexedIndirectCountKHR", (void *)CmdDrawIndexedIndirectCountKHR},
-    {"vkCmdSetExclusiveScissorNV", (void *)CmdSetExclusiveScissorNV},
-    {"vkCmdBindShadingRateImageNV", (void *)CmdBindShadingRateImageNV},
-    {"vkCmdSetViewportShadingRatePaletteNV", (void *)CmdSetViewportShadingRatePaletteNV},
-    {"vkCmdDrawMeshTasksNV", (void *)CmdDrawMeshTasksNV},
-    {"vkCmdDrawMeshTasksIndirectNV", (void *)CmdDrawMeshTasksIndirectNV},
-    {"vkCmdDrawMeshTasksIndirectCountNV", (void *)CmdDrawMeshTasksIndirectCountNV},
-    {"vkCreateRaytracingPipelinesNVX", (void *)CreateRaytracingPipelinesNVX},
-    {"vkCreateRenderPass2KHR", (void *)CreateRenderPass2KHR},
-    {"vkCmdBeginRenderPass2KHR", (void *)CmdBeginRenderPass2KHR},
-    {"vkCmdNextSubpass2KHR", (void *)CmdNextSubpass2KHR},
-    {"vkCmdEndRenderPass2KHR", (void *)CmdEndRenderPass2KHR},
-};
+void CoreChecks::CoreLayerDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache,
+                                                    const VkAllocationCallbacks *pAllocator) {
+    delete (ValidationCache *)validationCache;
+}
 
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
-    assert(device);
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+VkResult CoreChecks::CoreLayerGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize,
+                                                        void *pData) {
+    size_t inSize = *pDataSize;
+    ((ValidationCache *)validationCache)->Write(pDataSize, pData);
+    return (pData && *pDataSize != inSize) ? VK_INCOMPLETE : VK_SUCCESS;
+}
 
-    if (!ApiParentExtensionEnabled(funcName, device_data->extensions.device_extension_set)) {
-        return nullptr;
-    }
-    // Is API to be intercepted by this layer?
-    const auto &item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+VkResult CoreChecks::CoreLayerMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount,
+                                                       const VkValidationCacheEXT *pSrcCaches) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    auto dst = (ValidationCache *)dstCache;
+    auto src = (ValidationCache const *const *)pSrcCaches;
+    VkResult result = VK_SUCCESS;
+    for (uint32_t i = 0; i < srcCacheCount; i++) {
+        if (src[i] == dst) {
+            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT,
+                            0, "VUID-vkMergeValidationCachesEXT-dstCache-01536",
+                            "vkMergeValidationCachesEXT: dstCache (0x%" PRIx64 ") must not appear in pSrcCaches array.",
+                            HandleToUint64(dstCache));
+            result = VK_ERROR_VALIDATION_FAILED_EXT;
+        }
+        if (!skip) {
+            dst->Merge(src[i]);
+        }
     }
 
-    auto &table = device_data->dispatch_table;
-    if (!table.GetDeviceProcAddr) return nullptr;
-    return table.GetDeviceProcAddr(device, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    instance_layer_data *instance_data;
-    // Is API to be intercepted by this layer?
-    const auto &item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-
-    instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    auto &table = instance_data->dispatch_table;
-    if (!table.GetInstanceProcAddr) return nullptr;
-    return table.GetInstanceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
-    assert(instance);
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    auto &table = instance_data->dispatch_table;
-    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
-    return table.GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-}  // namespace core_validation
-
-// loader-layer interface v0, just wrappers since there is only a layer
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                                      VkExtensionProperties *pProperties) {
-    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
-                                                                                  VkLayerProperties *pProperties) {
-    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                                VkLayerProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                                                                    const char *pLayerName, uint32_t *pCount,
-                                                                                    VkExtensionProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
-    return core_validation::GetDeviceProcAddr(dev, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    return core_validation::GetInstanceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
-                                                                                           const char *funcName) {
-    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
-    assert(pVersionStruct != NULL);
-    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
-
-    // Fill in the function pointers if our version is at least capable of having the structure contain them.
-    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
-        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
-        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
-        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
-    }
-
-    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
-    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-    }
-
-    return VK_SUCCESS;
+    return result;
 }
diff --git a/layers/core_validation.h b/layers/core_validation.h
index 8a73973..333e28a 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,14 +19,19 @@
  * Author: Tobin Ehlis <tobine@google.com>
  * Author: Chris Forbes <chrisf@ijw.co.nz>
  * Author: Mark Lobodzinski <mark@lunarg.com>
+ * Author: Dave Houlton <daveh@lunarg.com>
  */
 
 #pragma once
 #include "core_validation_error_enums.h"
 #include "core_validation_types.h"
 #include "descriptor_sets.h"
+#include "shader_validation.h"
+#include "gpu_validation.h"
 #include "vk_layer_logging.h"
 #include "vulkan/vk_layer.h"
+#include "vk_typemap_helper.h"
+#include "vk_layer_data.h"
 #include <atomic>
 #include <functional>
 #include <memory>
@@ -36,37 +41,6 @@
 #include <list>
 #include <deque>
 
-/*
- * MTMTODO : Update this comment
- * Data Structure overview
- *  There are 4 global STL(' maps
- *  cbMap -- map of command Buffer (CB) objects to MT_CB_INFO structures
- *    Each MT_CB_INFO struct has an stl list container with
- *    memory objects that are referenced by this CB
- *  memObjMap -- map of Memory Objects to MT_MEM_OBJ_INFO structures
- *    Each MT_MEM_OBJ_INFO has two stl list containers with:
- *      -- all CBs referencing this mem obj
- *      -- all VK Objects that are bound to this memory
- *  objectMap -- map of objects to MT_OBJ_INFO structures
- *
- * Algorithm overview
- * These are the primary events that should happen related to different objects
- * 1. Command buffers
- *   CREATION - Add object,structure to map
- *   CMD BIND - If mem associated, add mem reference to list container
- *   DESTROY  - Remove from map, decrement (and report) mem references
- * 2. Mem Objects
- *   CREATION - Add object,structure to map
- *   OBJ BIND - Add obj structure to list container for that mem node
- *   CMB BIND - If mem-related add CB structure to list container for that mem node
- *   DESTROY  - Flag as errors any remaining refs and remove from map
- * 3. Generic Objects
- *   MEM BIND - DESTROY any previous binding, Add obj node w/ ref to map, add obj ref to list container for that mem node
- *   DESTROY - If mem bound, remove reference list container for that memInfo, remove object ref from map
- */
-// TODO : Is there a way to track when Cmd Buffer finishes & remove mem references at that point?
-// TODO : Could potentially store a list of freed mem allocs to flag when they're incorrectly used
-
 enum SyncScope {
     kSyncScopeInternal,
     kSyncScopeExternalTemporary,
@@ -137,12 +111,37 @@
     uint32_t display_plane_property_count = 0;
 };
 
+// This structure is used to save data across the CreateGraphicsPipelines down-chain API call
+struct create_graphics_pipeline_api_state {
+    std::vector<safe_VkGraphicsPipelineCreateInfo> gpu_create_infos;
+    std::vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
+    const VkGraphicsPipelineCreateInfo* pCreateInfos;
+};
+
+// This structure is used modify parameters for the CreatePipelineLayout down-chain API call
+struct create_pipeline_layout_api_state {
+    std::vector<VkDescriptorSetLayout> new_layouts;
+    VkPipelineLayoutCreateInfo modified_create_info;
+};
+
+// This structure is used modify and pass parameters for the CreateShaderModule down-chain API call
+
+struct create_shader_module_api_state {
+    uint32_t unique_shader_id;
+    VkShaderModuleCreateInfo instrumented_create_info;
+    std::vector<unsigned int> instrumented_pgm;
+};
+
 struct GpuQueue {
     VkPhysicalDevice gpu;
     uint32_t queue_family_index;
 };
 
-inline bool operator==(GpuQueue const &lhs, GpuQueue const &rhs) {
+struct SubresourceRangeErrorCodes {
+    const char *base_mip_err, *mip_count_err, *base_layer_err, *layer_count_err;
+};
+
+inline bool operator==(GpuQueue const& lhs, GpuQueue const& rhs) {
     return (lhs.gpu == rhs.gpu && lhs.queue_family_index == rhs.queue_family_index);
 }
 
@@ -157,10 +156,1462 @@
 
 struct SURFACE_STATE {
     VkSurfaceKHR surface = VK_NULL_HANDLE;
-    SWAPCHAIN_NODE *swapchain = nullptr;
-    SWAPCHAIN_NODE *old_swapchain = nullptr;
+    SWAPCHAIN_NODE* swapchain = nullptr;
     std::unordered_map<GpuQueue, bool> gpu_queue_support;
 
     SURFACE_STATE() {}
     SURFACE_STATE(VkSurfaceKHR surface) : surface(surface) {}
 };
+
+using std::unordered_map;
+
+class CoreChecks : public ValidationObject {
+   public:
+    std::unordered_set<VkQueue> queues;  // All queues under given device
+    unordered_map<VkSampler, std::unique_ptr<SAMPLER_STATE>> samplerMap;
+    unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
+    unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> imageMap;
+    unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
+    unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> bufferMap;
+    unordered_map<VkPipeline, std::unique_ptr<PIPELINE_STATE>> pipelineMap;
+    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
+    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE*> descriptorPoolMap;
+    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet*> setMap;
+    unordered_map<VkDescriptorSetLayout, std::shared_ptr<cvdescriptorset::DescriptorSetLayout>> descriptorSetLayoutMap;
+    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
+    unordered_map<VkDeviceMemory, std::unique_ptr<DEVICE_MEM_INFO>> memObjMap;
+    unordered_map<VkFence, FENCE_NODE> fenceMap;
+    unordered_map<VkQueue, QUEUE_STATE> queueMap;
+    unordered_map<VkEvent, EVENT_STATE> eventMap;
+    unordered_map<QueryObject, bool> queryToStateMap;
+    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
+    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
+    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE*> commandBufferMap;
+    unordered_map<VkFramebuffer, std::unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
+    unordered_map<VkImage, std::vector<ImageSubresourcePair>> imageSubresourceMap;
+    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
+    unordered_map<VkRenderPass, std::shared_ptr<RENDER_PASS_STATE>> renderPassMap;
+    unordered_map<VkShaderModule, std::unique_ptr<shader_module>> shaderModuleMap;
+    unordered_map<VkDescriptorUpdateTemplateKHR, std::unique_ptr<TEMPLATE_STATE>> desc_template_map;
+    unordered_map<VkSwapchainKHR, std::unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
+    unordered_map<VkSamplerYcbcrConversion, uint64_t> ycbcr_conversion_ahb_fmt_map;
+    std::unordered_set<uint64_t> ahb_ext_formats_set;
+    GlobalQFOTransferBarrierMap<VkImageMemoryBarrier> qfo_release_image_barrier_map;
+    GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier> qfo_release_buffer_barrier_map;
+    // Map for queue family index to queue count
+    unordered_map<uint32_t, uint32_t> queue_family_index_map;
+
+    // Used for instance versions of this object
+    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
+    // Link to the device's physical-device data
+    PHYSICAL_DEVICE_STATE* physical_device_state;
+    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
+
+    // Link for derived device objects back to their parent instance object
+    CoreChecks* instance_state;
+
+    // Temporary object pointers
+    layer_data* device_data = this;
+    layer_data* instance_data = this;
+    layer_data* dev_data = this;
+    std::unordered_map<void*, layer_data*> layer_data_map;
+    std::unordered_map<void*, layer_data*> instance_layer_data_map;
+
+    dispatch_key get_dispatch_key(const void* object) { return nullptr; }
+
+    template <typename DATA_T>
+    DATA_T* GetLayerDataPtr(void* data_key, std::unordered_map<void*, DATA_T*>& layer_data_map) {
+        return this;
+    }
+
+    DeviceFeatures enabled_features = {};
+    // Device specific data
+    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
+    VkPhysicalDeviceProperties phys_dev_props = {};
+    // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain
+    struct DeviceExtensionProperties {
+        uint32_t max_push_descriptors;  // from VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors
+        VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_props;
+        VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
+        VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
+        VkPhysicalDeviceInlineUniformBlockPropertiesEXT inline_uniform_block_props;
+        VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vtx_attrib_divisor_props;
+        VkPhysicalDeviceDepthStencilResolvePropertiesKHR depth_stencil_resolve_props;
+    };
+    DeviceExtensionProperties phys_dev_ext_props = {};
+    bool external_sync_warning = false;
+    uint32_t api_version = 0;
+    GpuValidationState gpu_validation_state = {};
+    uint32_t physical_device_count;
+
+    // Class Declarations for helper functions
+    cvdescriptorset::DescriptorSet* GetSetNode(VkDescriptorSet);
+    DESCRIPTOR_POOL_STATE* GetDescriptorPoolState(const VkDescriptorPool);
+    BUFFER_STATE* GetBufferState(VkBuffer);
+    IMAGE_STATE* GetImageState(VkImage);
+    DEVICE_MEM_INFO* GetMemObjInfo(VkDeviceMemory);
+    BUFFER_VIEW_STATE* GetBufferViewState(VkBufferView);
+    SAMPLER_STATE* GetSamplerState(VkSampler);
+    IMAGE_VIEW_STATE* GetAttachmentImageViewState(FRAMEBUFFER_STATE* framebuffer, uint32_t index);
+    IMAGE_VIEW_STATE* GetImageViewState(VkImageView);
+    SWAPCHAIN_NODE* GetSwapchainNode(VkSwapchainKHR);
+    GLOBAL_CB_NODE* GetCBNode(const VkCommandBuffer cb);
+    PIPELINE_STATE* GetPipelineState(VkPipeline pipeline);
+    RENDER_PASS_STATE* GetRenderPassState(VkRenderPass renderpass);
+    std::shared_ptr<RENDER_PASS_STATE> GetRenderPassStateSharedPtr(VkRenderPass renderpass);
+    FRAMEBUFFER_STATE* GetFramebufferState(VkFramebuffer framebuffer);
+    COMMAND_POOL_NODE* GetCommandPoolNode(VkCommandPool pool);
+    shader_module const* GetShaderModuleState(VkShaderModule module);
+    const DeviceFeatures* GetEnabledFeatures();
+    FENCE_NODE* GetFenceNode(VkFence fence);
+    EVENT_STATE* GetEventNode(VkEvent event);
+    QUERY_POOL_NODE* GetQueryPoolNode(VkQueryPool query_pool);
+    QUEUE_STATE* GetQueueState(VkQueue queue);
+    SEMAPHORE_NODE* GetSemaphoreNode(VkSemaphore semaphore);
+    PHYSICAL_DEVICE_STATE* GetPhysicalDeviceState(VkPhysicalDevice phys);
+    PHYSICAL_DEVICE_STATE* GetPhysicalDeviceState();
+    SURFACE_STATE* GetSurfaceState(VkSurfaceKHR surface);
+    BINDABLE* GetObjectMemBinding(uint64_t handle, VulkanObjectType type);
+
+    bool VerifyQueueStateToSeq(layer_data* dev_data, QUEUE_STATE* initial_queue, uint64_t initial_seq);
+    void ClearCmdBufAndMemReferences(layer_data* dev_data, GLOBAL_CB_NODE* cb_node);
+    void ClearMemoryObjectBinding(uint64_t handle, VulkanObjectType type, VkDeviceMemory mem);
+    void ResetCommandBufferState(layer_data* dev_data, const VkCommandBuffer cb);
+    void SetMemBinding(layer_data* dev_data, VkDeviceMemory mem, BINDABLE* mem_binding, VkDeviceSize memory_offset, uint64_t handle,
+                       VulkanObjectType type);
+    bool ValidateSetMemBinding(layer_data* dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
+                               const char* apiName);
+    bool SetSparseMemBinding(layer_data* dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type);
+    bool ValidateDeviceQueueFamily(layer_data* device_data, uint32_t queue_family, const char* cmd_name, const char* parameter_name,
+                                   const char* error_code, bool optional);
+    BASE_NODE* GetStateStructPtrFromObject(layer_data* dev_data, VK_OBJECT object_struct);
+    void RemoveCommandBufferBinding(layer_data* dev_data, VK_OBJECT const* object, GLOBAL_CB_NODE* cb_node);
+    bool ValidateBindBufferMemory(layer_data* device_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                  const char* api_name);
+    void RecordGetBufferMemoryRequirementsState(layer_data* device_data, VkBuffer buffer,
+                                                VkMemoryRequirements* pMemoryRequirements);
+    void UpdateBindBufferMemoryState(layer_data* device_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset);
+    PIPELINE_LAYOUT_NODE const* GetPipelineLayout(layer_data const* dev_data, VkPipelineLayout pipeLayout);
+    const TEMPLATE_STATE* GetDescriptorTemplateState(const layer_data* dev_data,
+                                                     VkDescriptorUpdateTemplateKHR descriptor_update_template);
+    bool ValidateGetImageMemoryRequirements2(layer_data* dev_data, const VkImageMemoryRequirementsInfo2* pInfo);
+    void RecordGetImageMemoryRequiementsState(layer_data* device_data, VkImage image, VkMemoryRequirements* pMemoryRequirements);
+    void FreeCommandBufferStates(layer_data* dev_data, COMMAND_POOL_NODE* pool_state, const uint32_t command_buffer_count,
+                                 const VkCommandBuffer* command_buffers);
+    bool CheckCommandBuffersInFlight(layer_data* dev_data, COMMAND_POOL_NODE* pPool, const char* action, const char* error_code);
+    bool CheckCommandBufferInFlight(layer_data* dev_data, const GLOBAL_CB_NODE* cb_node, const char* action,
+                                    const char* error_code);
+    bool VerifyQueueStateToFence(layer_data* dev_data, VkFence fence);
+    void DecrementBoundResources(layer_data* dev_data, GLOBAL_CB_NODE const* cb_node);
+    bool VerifyWaitFenceState(layer_data* dev_data, VkFence fence, const char* apiCall);
+    void RetireFence(layer_data* dev_data, VkFence fence);
+    void StoreMemRanges(layer_data* dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size);
+    bool ValidateIdleDescriptorSet(const layer_data* dev_data, VkDescriptorSet set, const char* func_str);
+    void InitializeAndTrackMemory(layer_data* dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, void** ppData);
+    bool ValidatePipelineLocked(layer_data* dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const& pPipelines,
+                                int pipelineIndex);
+    bool ValidatePipelineUnlocked(layer_data* dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const& pPipelines,
+                                  int pipelineIndex);
+    void FreeDescriptorSet(layer_data* dev_data, cvdescriptorset::DescriptorSet* descriptor_set);
+    void DeletePools(layer_data* dev_data);
+    bool ValidImageBufferQueue(layer_data* dev_data, GLOBAL_CB_NODE* cb_node, const VK_OBJECT* object, VkQueue queue,
+                               uint32_t count, const uint32_t* indices);
+    bool ValidateFenceForSubmit(layer_data* dev_data, FENCE_NODE* pFence);
+    void AddMemObjInfo(layer_data* dev_data, void* object, const VkDeviceMemory mem, const VkMemoryAllocateInfo* pAllocateInfo);
+    bool ValidateStatus(layer_data* dev_data, GLOBAL_CB_NODE* pNode, CBStatusFlags status_mask, VkFlags msg_flags,
+                        const char* fail_msg, const char* msg_code);
+    bool ValidateDrawStateFlags(layer_data* dev_data, GLOBAL_CB_NODE* pCB, const PIPELINE_STATE* pPipe, bool indexed,
+                                const char* msg_code);
+    bool LogInvalidAttachmentMessage(layer_data const* dev_data, const char* type1_string, const RENDER_PASS_STATE* rp1_state,
+                                     const char* type2_string, const RENDER_PASS_STATE* rp2_state, uint32_t primary_attach,
+                                     uint32_t secondary_attach, const char* msg, const char* caller, const char* error_code);
+    bool ValidateAttachmentCompatibility(layer_data const* dev_data, const char* type1_string, const RENDER_PASS_STATE* rp1_state,
+                                         const char* type2_string, const RENDER_PASS_STATE* rp2_state, uint32_t primary_attach,
+                                         uint32_t secondary_attach, const char* caller, const char* error_code);
+    bool ValidateSubpassCompatibility(layer_data const* dev_data, const char* type1_string, const RENDER_PASS_STATE* rp1_state,
+                                      const char* type2_string, const RENDER_PASS_STATE* rp2_state, const int subpass,
+                                      const char* caller, const char* error_code);
+    bool ValidateRenderPassCompatibility(layer_data const* dev_data, const char* type1_string, const RENDER_PASS_STATE* rp1_state,
+                                         const char* type2_string, const RENDER_PASS_STATE* rp2_state, const char* caller,
+                                         const char* error_code);
+    void UpdateDrawState(layer_data* dev_data, GLOBAL_CB_NODE* cb_state, const VkPipelineBindPoint bind_point);
+    bool ReportInvalidCommandBuffer(layer_data* dev_data, const GLOBAL_CB_NODE* cb_state, const char* call_source);
+    void InitGpuValidation(layer_data* instance_data);
+
+    bool ValidatePipelineVertexDivisors(layer_data* dev_data, std::vector<std::unique_ptr<PIPELINE_STATE>> const& pipe_state_vec,
+                                        const uint32_t count, const VkGraphicsPipelineCreateInfo* pipe_cis);
+    void AddFramebufferBinding(layer_data* dev_data, GLOBAL_CB_NODE* cb_state, FRAMEBUFFER_STATE* fb_state);
+    bool ValidateImageBarrierImage(layer_data* device_data, const char* funcName, GLOBAL_CB_NODE const* cb_state,
+                                   VkFramebuffer framebuffer, uint32_t active_subpass,
+                                   const safe_VkSubpassDescription2KHR& sub_desc, uint64_t rp_handle, uint32_t img_index,
+                                   const VkImageMemoryBarrier& img_barrier);
+    void RecordCmdBeginRenderPassState(layer_data* device_data, VkCommandBuffer commandBuffer,
+                                       const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassContents contents);
+    bool ValidateCmdBeginRenderPass(layer_data* device_data, VkCommandBuffer commandBuffer, RenderPassCreateVersion rp_version,
+                                    const VkRenderPassBeginInfo* pRenderPassBegin);
+    bool ValidateDependencies(layer_data* dev_data, FRAMEBUFFER_STATE const* framebuffer, RENDER_PASS_STATE const* renderPass);
+    bool ValidateBarriers(layer_data* device_data, const char* funcName, GLOBAL_CB_NODE* cb_state,
+                          VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, uint32_t memBarrierCount,
+                          const VkMemoryBarrier* pMemBarriers, uint32_t bufferBarrierCount,
+                          const VkBufferMemoryBarrier* pBufferMemBarriers, uint32_t imageMemBarrierCount,
+                          const VkImageMemoryBarrier* pImageMemBarriers);
+    bool ValidateCreateSwapchain(layer_data* device_data, const char* func_name, VkSwapchainCreateInfoKHR const* pCreateInfo,
+                                 SURFACE_STATE* surface_state, SWAPCHAIN_NODE* old_swapchain_state);
+    void RecordCmdPushDescriptorSetState(layer_data* device_data, GLOBAL_CB_NODE* cb_state, VkPipelineBindPoint pipelineBindPoint,
+                                         VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                         const VkWriteDescriptorSet* pDescriptorWrites);
+    bool ValidatePipelineBindPoint(layer_data* device_data, GLOBAL_CB_NODE* cb_state, VkPipelineBindPoint bind_point,
+                                   const char* func_name, const std::map<VkPipelineBindPoint, std::string>& bind_errors);
+    bool ValidateMemoryIsMapped(layer_data* dev_data, const char* funcName, uint32_t memRangeCount,
+                                const VkMappedMemoryRange* pMemRanges);
+    bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data* dev_data, uint32_t mem_range_count,
+                                                  const VkMappedMemoryRange* mem_ranges);
+    void CopyNoncoherentMemoryFromDriver(layer_data* dev_data, uint32_t mem_range_count, const VkMappedMemoryRange* mem_ranges);
+    bool ValidateMappedMemoryRangeDeviceLimits(layer_data* dev_data, const char* func_name, uint32_t mem_range_count,
+                                               const VkMappedMemoryRange* mem_ranges);
+    BarrierOperationsType ComputeBarrierOperationsType(layer_data* device_data, GLOBAL_CB_NODE* cb_state,
+                                                       uint32_t buffer_barrier_count, const VkBufferMemoryBarrier* buffer_barriers,
+                                                       uint32_t image_barrier_count, const VkImageMemoryBarrier* image_barriers);
+    bool ValidateStageMasksAgainstQueueCapabilities(layer_data* dev_data, GLOBAL_CB_NODE const* cb_state,
+                                                    VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
+                                                    BarrierOperationsType barrier_op_type, const char* function,
+                                                    const char* error_code);
+    bool SetEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+    bool ValidateRenderPassImageBarriers(layer_data* device_data, const char* funcName, GLOBAL_CB_NODE* cb_state,
+                                         uint32_t active_subpass, const safe_VkSubpassDescription2KHR& sub_desc, uint64_t rp_handle,
+                                         const safe_VkSubpassDependency2KHR* dependencies,
+                                         const std::vector<uint32_t>& self_dependencies, uint32_t image_mem_barrier_count,
+                                         const VkImageMemoryBarrier* image_barriers);
+    bool ValidateSecondaryCommandBufferState(layer_data* dev_data, GLOBAL_CB_NODE* pCB, GLOBAL_CB_NODE* pSubCB);
+    bool ValidateFramebuffer(layer_data* dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE* pCB,
+                             VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE* pSubCB, const char* caller);
+    bool ValidateDescriptorUpdateTemplate(const char* func_name, layer_data* device_data,
+                                          const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo);
+    bool ValidateCreateSamplerYcbcrConversion(const layer_data* device_data, const char* func_name,
+                                              const VkSamplerYcbcrConversionCreateInfo* create_info);
+    void RecordCreateSamplerYcbcrConversionState(layer_data* device_data, const VkSamplerYcbcrConversionCreateInfo* create_info,
+                                                 VkSamplerYcbcrConversion ycbcr_conversion);
+    bool ValidateImportFence(layer_data* device_data, VkFence fence, const char* caller_name);
+    void RecordImportFenceState(layer_data* device_data, VkFence fence, VkExternalFenceHandleTypeFlagBitsKHR handle_type,
+                                VkFenceImportFlagsKHR flags);
+    void RecordGetExternalFenceState(layer_data* device_data, VkFence fence, VkExternalFenceHandleTypeFlagBitsKHR handle_type);
+    bool ValidateAcquireNextImage(layer_data* device_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                  VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex, const char* func_name);
+    void RecordAcquireNextImageState(layer_data* device_data, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
+                                     VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
+    bool VerifyRenderAreaBounds(const layer_data* dev_data, const VkRenderPassBeginInfo* pRenderPassBegin);
+    bool ValidatePrimaryCommandBuffer(const layer_data* dev_data, const GLOBAL_CB_NODE* pCB, char const* cmd_name,
+                                      const char* error_code);
+    void RecordCmdNextSubpass(layer_data* device_data, VkCommandBuffer commandBuffer, VkSubpassContents contents);
+    bool ValidateCmdEndRenderPass(layer_data* device_data, RenderPassCreateVersion rp_version, VkCommandBuffer commandBuffer);
+    void RecordCmdEndRenderPassState(layer_data* device_data, VkCommandBuffer commandBuffer);
+    bool ValidateFramebufferCreateInfo(layer_data* dev_data, const VkFramebufferCreateInfo* pCreateInfo);
+    bool MatchUsage(layer_data* dev_data, uint32_t count, const VkAttachmentReference2KHR* attachments,
+                    const VkFramebufferCreateInfo* fbci, VkImageUsageFlagBits usage_flag, const char* error_code);
+    bool CheckDependencyExists(const layer_data* dev_data, const uint32_t subpass, const std::vector<uint32_t>& dependent_subpasses,
+                               const std::vector<DAGNode>& subpass_to_node, bool& skip);
+    bool CheckPreserved(const layer_data* dev_data, const VkRenderPassCreateInfo2KHR* pCreateInfo, const int index,
+                        const uint32_t attachment, const std::vector<DAGNode>& subpass_to_node, int depth, bool& skip);
+    bool ValidateBindImageMemory(layer_data* device_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                 const char* api_name);
+    void UpdateBindImageMemoryState(layer_data* device_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset);
+    void RecordGetPhysicalDeviceDisplayPlanePropertiesState(instance_layer_data* instance_data, VkPhysicalDevice physicalDevice,
+                                                            uint32_t* pPropertyCount, void* pProperties);
+    bool ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data* instance_data,
+                                                                 VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                 const char* api_name);
+    bool ValidateQuery(VkQueue queue, GLOBAL_CB_NODE* pCB, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
+    bool IsQueryInvalid(layer_data* dev_data, QUEUE_STATE* queue_data, VkQueryPool queryPool, uint32_t queryIndex);
+    bool ValidateImportSemaphore(layer_data* device_data, VkSemaphore semaphore, const char* caller_name);
+    void RecordImportSemaphoreState(layer_data* device_data, VkSemaphore semaphore,
+                                    VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type, VkSemaphoreImportFlagsKHR flags);
+    void RecordGetExternalSemaphoreState(layer_data* device_data, VkSemaphore semaphore,
+                                         VkExternalSemaphoreHandleTypeFlagBitsKHR handle_type);
+    bool SetQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value);
+    bool ValidateCmdDrawType(layer_data* dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
+                             CMD_TYPE cmd_type, const char* caller, VkQueueFlags queue_flags, const char* queue_flag_code,
+                             const char* renderpass_msg_code, const char* pipebound_msg_code, const char* dynamic_state_msg_code);
+    void UpdateStateCmdDrawDispatchType(layer_data* dev_data, GLOBAL_CB_NODE* cb_state, VkPipelineBindPoint bind_point);
+    void UpdateStateCmdDrawType(layer_data* dev_data, GLOBAL_CB_NODE* cb_state, VkPipelineBindPoint bind_point);
+    bool ValidateCmdNextSubpass(layer_data* device_data, RenderPassCreateVersion rp_version, VkCommandBuffer commandBuffer);
+    bool RangesIntersect(layer_data const* dev_data, MEMORY_RANGE const* range1, VkDeviceSize offset, VkDeviceSize end);
+    bool RangesIntersect(layer_data const* dev_data, MEMORY_RANGE const* range1, MEMORY_RANGE const* range2, bool* skip,
+                         bool skip_checks);
+    bool ValidateInsertMemoryRange(layer_data const* dev_data, uint64_t handle, DEVICE_MEM_INFO* mem_info,
+                                   VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image, bool is_linear,
+                                   const char* api_name);
+    void InsertMemoryRange(layer_data const* dev_data, uint64_t handle, DEVICE_MEM_INFO* mem_info, VkDeviceSize memoryOffset,
+                           VkMemoryRequirements memRequirements, bool is_image, bool is_linear);
+    bool ValidateInsertImageMemoryRange(layer_data const* dev_data, VkImage image, DEVICE_MEM_INFO* mem_info,
+                                        VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
+                                        const char* api_name);
+    void InsertImageMemoryRange(layer_data const* dev_data, VkImage image, DEVICE_MEM_INFO* mem_info, VkDeviceSize mem_offset,
+                                VkMemoryRequirements mem_reqs, bool is_linear);
+    bool ValidateInsertBufferMemoryRange(layer_data const* dev_data, VkBuffer buffer, DEVICE_MEM_INFO* mem_info,
+                                         VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char* api_name);
+    void InsertBufferMemoryRange(layer_data const* dev_data, VkBuffer buffer, DEVICE_MEM_INFO* mem_info, VkDeviceSize mem_offset,
+                                 VkMemoryRequirements mem_reqs);
+    bool ValidateMemoryTypes(const layer_data* dev_data, const DEVICE_MEM_INFO* mem_info, const uint32_t memory_type_bits,
+                             const char* funcName, const char* msgCode);
+    bool ValidateCommandBufferState(layer_data* dev_data, GLOBAL_CB_NODE* cb_state, const char* call_source,
+                                    int current_submit_count, const char* vu_id);
+    bool ValidateCommandBufferSimultaneousUse(layer_data* dev_data, GLOBAL_CB_NODE* pCB, int current_submit_count);
+    bool ValidateGetDeviceQueue(layer_data* device_data, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue,
+                                const char* valid_qfi_vuid, const char* qfi_in_range_vuid);
+    void RecordGetDeviceQueueState(layer_data* device_data, uint32_t queue_family_index, VkQueue queue);
+    bool ValidateRenderpassAttachmentUsage(const layer_data* dev_data, RenderPassCreateVersion rp_version,
+                                           const VkRenderPassCreateInfo2KHR* pCreateInfo);
+    bool AddAttachmentUse(const layer_data* dev_data, RenderPassCreateVersion rp_version, uint32_t subpass,
+                          std::vector<uint8_t>& attachment_uses, std::vector<VkImageLayout>& attachment_layouts,
+                          uint32_t attachment, uint8_t new_use, VkImageLayout new_layout);
+    bool ValidateAttachmentIndex(const layer_data* dev_data, RenderPassCreateVersion rp_version, uint32_t attachment,
+                                 uint32_t attachment_count, const char* type);
+    bool ValidateCreateRenderPass(layer_data* dev_data, VkDevice device, RenderPassCreateVersion rp_version,
+                                  const VkRenderPassCreateInfo2KHR* pCreateInfo, RENDER_PASS_STATE* render_pass);
+    bool ValidateRenderPassPipelineBarriers(layer_data* device_data, const char* funcName, GLOBAL_CB_NODE* cb_state,
+                                            VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
+                                            VkDependencyFlags dependency_flags, uint32_t mem_barrier_count,
+                                            const VkMemoryBarrier* mem_barriers, uint32_t buffer_mem_barrier_count,
+                                            const VkBufferMemoryBarrier* buffer_mem_barriers, uint32_t image_mem_barrier_count,
+                                            const VkImageMemoryBarrier* image_barriers);
+    bool CheckStageMaskQueueCompatibility(layer_data* dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
+                                          VkQueueFlags queue_flags, const char* function, const char* src_or_dest,
+                                          const char* error_code);
+    void RecordUpdateDescriptorSetWithTemplateState(layer_data* device_data, VkDescriptorSet descriptorSet,
+                                                    VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
+    bool ValidateUpdateDescriptorSetWithTemplate(layer_data* device_data, VkDescriptorSet descriptorSet,
+                                                 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
+    bool ValidateMemoryIsBoundToBuffer(const layer_data*, const BUFFER_STATE*, const char*, const char*);
+    bool ValidateMemoryIsBoundToImage(const layer_data*, const IMAGE_STATE*, const char*, const char*);
+    void AddCommandBufferBindingSampler(GLOBAL_CB_NODE*, SAMPLER_STATE*);
+    void AddCommandBufferBindingImage(const layer_data*, GLOBAL_CB_NODE*, IMAGE_STATE*);
+    void AddCommandBufferBindingImageView(const layer_data*, GLOBAL_CB_NODE*, IMAGE_VIEW_STATE*);
+    void AddCommandBufferBindingBuffer(const layer_data*, GLOBAL_CB_NODE*, BUFFER_STATE*);
+    void AddCommandBufferBindingBufferView(const layer_data*, GLOBAL_CB_NODE*, BUFFER_VIEW_STATE*);
+    bool ValidateObjectNotInUse(const layer_data* dev_data, BASE_NODE* obj_node, VK_OBJECT obj_struct, const char* caller_name,
+                                const char* error_code);
+    void InvalidateCommandBuffers(const layer_data* dev_data, std::unordered_set<GLOBAL_CB_NODE*> const& cb_nodes, VK_OBJECT obj);
+    void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO* mem_info);
+    void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO* mem_info);
+    void ClearMemoryObjectBindings(uint64_t handle, VulkanObjectType type);
+    bool ValidateCmdQueueFlags(layer_data* dev_data, const GLOBAL_CB_NODE* cb_node, const char* caller_name, VkQueueFlags flags,
+                               const char* error_code);
+    bool InsideRenderPass(const layer_data* my_data, const GLOBAL_CB_NODE* pCB, const char* apiName, const char* msgCode);
+    bool OutsideRenderPass(const layer_data* my_data, GLOBAL_CB_NODE* pCB, const char* apiName, const char* msgCode);
+
+    void SetLayout(layer_data* device_data, GLOBAL_CB_NODE* pCB, ImageSubresourcePair imgpair, const VkImageLayout& layout);
+    void SetLayout(layer_data* device_data, GLOBAL_CB_NODE* pCB, ImageSubresourcePair imgpair,
+                   const IMAGE_CMD_BUF_LAYOUT_NODE& node);
+    void SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE>& imageLayoutMap, ImageSubresourcePair imgpair,
+                   VkImageLayout layout);
+
+    bool ValidateImageSampleCount(layer_data* dev_data, IMAGE_STATE* image_state, VkSampleCountFlagBits sample_count,
+                                  const char* location, const std::string& msgCode);
+    bool ValidateCmdSubpassState(const layer_data* dev_data, const GLOBAL_CB_NODE* pCB, const CMD_TYPE cmd_type);
+    bool ValidateCmd(layer_data* dev_data, const GLOBAL_CB_NODE* cb_state, const CMD_TYPE cmd, const char* caller_name);
+
+    // Prototypes for layer_data accessor functions.  These should be in their own header file at some point
+    VkFormatProperties GetPDFormatProperties(const VkFormat format);
+    VkResult GetPDImageFormatProperties(const VkImageCreateInfo*, VkImageFormatProperties*);
+    VkResult GetPDImageFormatProperties2(const VkPhysicalDeviceImageFormatInfo2*, VkImageFormatProperties2*);
+    const debug_report_data* GetReportData();
+    const VkLayerDispatchTable* GetDispatchTable();
+    const VkPhysicalDeviceProperties* GetPDProperties();
+    const VkPhysicalDeviceMemoryProperties* GetPhysicalDeviceMemoryProperties();
+    const CHECK_DISABLED* GetDisables();
+    const CHECK_ENABLED* GetEnables();
+    std::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>>* GetImageMap();
+    std::unordered_map<VkImage, std::vector<ImageSubresourcePair>>* GetImageSubresourceMap();
+    std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE>* GetImageLayoutMap();
+    std::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>>* GetBufferMap();
+    std::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>>* GetBufferViewMap();
+    std::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>>* GetImageViewMap();
+    std::unordered_map<VkSamplerYcbcrConversion, uint64_t>* GetYcbcrConversionFormatMap();
+    std::unordered_set<uint64_t>* GetAHBExternalFormatsSet();
+
+    const DeviceExtensions* GetDeviceExtensions();
+    GpuValidationState* GetGpuValidationState();
+    VkDevice GetDevice();
+
+    uint32_t GetApiVersion();
+
+    GlobalQFOTransferBarrierMap<VkImageMemoryBarrier>& GetGlobalQFOReleaseBarrierMap(
+        const QFOTransferBarrier<VkImageMemoryBarrier>::Tag& type_tag);
+    GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier>& GetGlobalQFOReleaseBarrierMap(
+        const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag& type_tag);
+    template <typename Barrier>
+    void RecordQueuedQFOTransferBarriers(layer_data* device_data, GLOBAL_CB_NODE* cb_state);
+    template <typename Barrier>
+    bool ValidateQueuedQFOTransferBarriers(layer_data* device_data, GLOBAL_CB_NODE* cb_state,
+                                           QFOTransferCBScoreboards<Barrier>* scoreboards);
+    bool ValidateQueuedQFOTransfers(layer_data* device_data, GLOBAL_CB_NODE* cb_state,
+                                    QFOTransferCBScoreboards<VkImageMemoryBarrier>* qfo_image_scoreboards,
+                                    QFOTransferCBScoreboards<VkBufferMemoryBarrier>* qfo_buffer_scoreboards);
+    template <typename BarrierRecord, typename Scoreboard>
+    bool ValidateAndUpdateQFOScoreboard(const debug_report_data* report_data, const GLOBAL_CB_NODE* cb_state, const char* operation,
+                                        const BarrierRecord& barrier, Scoreboard* scoreboard);
+    template <typename Barrier>
+    void RecordQFOTransferBarriers(layer_data* device_data, GLOBAL_CB_NODE* cb_state, uint32_t barrier_count,
+                                   const Barrier* barriers);
+    void RecordBarriersQFOTransfers(layer_data* device_data, GLOBAL_CB_NODE* cb_state, uint32_t bufferBarrierCount,
+                                    const VkBufferMemoryBarrier* pBufferMemBarriers, uint32_t imageMemBarrierCount,
+                                    const VkImageMemoryBarrier* pImageMemBarriers);
+    template <typename Barrier>
+    bool ValidateQFOTransferBarrierUniqueness(layer_data* device_data, const char* func_name, GLOBAL_CB_NODE* cb_state,
+                                              uint32_t barrier_count, const Barrier* barriers);
+    bool IsReleaseOp(GLOBAL_CB_NODE* cb_state, VkImageMemoryBarrier const* barrier);
+    bool ValidateBarriersQFOTransferUniqueness(layer_data* device_data, const char* func_name, GLOBAL_CB_NODE* cb_state,
+                                               uint32_t bufferBarrierCount, const VkBufferMemoryBarrier* pBufferMemBarriers,
+                                               uint32_t imageMemBarrierCount, const VkImageMemoryBarrier* pImageMemBarriers);
+    bool ValidatePrimaryCommandBufferState(layer_data* dev_data, GLOBAL_CB_NODE* pCB, int current_submit_count,
+                                           QFOTransferCBScoreboards<VkImageMemoryBarrier>* qfo_image_scoreboards,
+                                           QFOTransferCBScoreboards<VkBufferMemoryBarrier>* qfo_buffer_scoreboards);
+    bool ValidatePipelineDrawtimeState(layer_data const* dev_data, LAST_BOUND_STATE const& state, const GLOBAL_CB_NODE* pCB,
+                                       CMD_TYPE cmd_type, PIPELINE_STATE const* pPipeline, const char* caller);
+    bool ValidateCmdBufDrawState(layer_data* dev_data, GLOBAL_CB_NODE* cb_node, CMD_TYPE cmd_type, const bool indexed,
+                                 const VkPipelineBindPoint bind_point, const char* function, const char* pipe_err_code,
+                                 const char* state_err_code);
+    void IncrementBoundObjects(layer_data* dev_data, GLOBAL_CB_NODE const* cb_node);
+    void IncrementResources(layer_data* dev_data, GLOBAL_CB_NODE* cb_node);
+    bool ValidateEventStageMask(VkQueue queue, GLOBAL_CB_NODE* pCB, uint32_t eventCount, size_t firstEventIndex,
+                                VkPipelineStageFlags sourceStageMask);
+    void RetireWorkOnQueue(layer_data* dev_data, QUEUE_STATE* pQueue, uint64_t seq);
+    bool ValidateResources(layer_data* dev_data, GLOBAL_CB_NODE* cb_node);
+    bool ValidateQueueFamilyIndices(layer_data* dev_data, GLOBAL_CB_NODE* pCB, VkQueue queue);
+    VkResult CoreLayerCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo,
+                                               const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache);
+    void CoreLayerDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache,
+                                            const VkAllocationCallbacks* pAllocator);
+    VkResult CoreLayerMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount,
+                                               const VkValidationCacheEXT* pSrcCaches);
+    VkResult CoreLayerGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize,
+                                                void* pData);
+
+    // Descriptor Set Validation Functions
+    bool ValidateUpdateDescriptorSetsWithTemplateKHR(layer_data* device_data, VkDescriptorSet descriptorSet,
+                                                     const TEMPLATE_STATE* template_state, const void* pData);
+    void PerformUpdateDescriptorSetsWithTemplateKHR(layer_data* device_data, VkDescriptorSet descriptorSet,
+                                                    const TEMPLATE_STATE* template_state, const void* pData);
+    void UpdateAllocateDescriptorSetsData(const layer_data* dev_data, const VkDescriptorSetAllocateInfo*,
+                                          cvdescriptorset::AllocateDescriptorSetsData*);
+    bool ValidateAllocateDescriptorSets(const layer_data*, const VkDescriptorSetAllocateInfo*,
+                                        const cvdescriptorset::AllocateDescriptorSetsData*);
+    void PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo*, const VkDescriptorSet*,
+                                       const cvdescriptorset::AllocateDescriptorSetsData*,
+                                       std::unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE*>*,
+                                       std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet*>*, layer_data*);
+    bool ValidateUpdateDescriptorSets(const debug_report_data* report_data, const layer_data* dev_data, uint32_t write_count,
+                                      const VkWriteDescriptorSet* p_wds, uint32_t copy_count, const VkCopyDescriptorSet* p_cds,
+                                      const char* func_name);
+
+    // Stuff from shader_validation
+    bool ValidateAndCapturePipelineShaderState(layer_data* dev_data, PIPELINE_STATE* pPipeline);
+    bool ValidateComputePipeline(layer_data* dev_data, PIPELINE_STATE* pPipeline);
+    bool ValidateRayTracingPipelineNV(layer_data* dev_data, PIPELINE_STATE* pipeline);
+    bool PreCallValidateCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo,
+                                           const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule);
+    void PreCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo,
+                                         const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule, void* csm_state);
+    void PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo,
+                                          const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule, VkResult result,
+                                          void* csm_state);
+    bool ValidatePipelineShaderStage(layer_data* dev_data, VkPipelineShaderStageCreateInfo const* pStage, PIPELINE_STATE* pipeline,
+                                     shader_module const** out_module, spirv_inst_iter* out_entrypoint, bool check_point_size);
+    bool ValidatePointListShaderState(const layer_data* dev_data, const PIPELINE_STATE* pipeline, shader_module const* src,
+                                      spirv_inst_iter entrypoint, VkShaderStageFlagBits stage);
+    bool ValidateShaderCapabilities(layer_data* dev_data, shader_module const* src, VkShaderStageFlagBits stage,
+                                    bool has_writable_descriptor);
+    bool ValidateShaderStageInputOutputLimits(layer_data* dev_data, shader_module const* src,
+                                              VkPipelineShaderStageCreateInfo const* pStage, PIPELINE_STATE* pipeline);
+
+    // Gpu Validation Functions
+    void GpuPreCallRecordCreateDevice(VkPhysicalDevice gpu, std::unique_ptr<safe_VkDeviceCreateInfo>& modified_create_info,
+                                      VkPhysicalDeviceFeatures* supported_features);
+    void GpuPostCallRecordCreateDevice(layer_data* dev_data);
+    void GpuPreCallRecordDestroyDevice(layer_data* dev_data);
+    void GpuPreCallRecordFreeCommandBuffers(layer_data* dev_data, uint32_t commandBufferCount,
+                                            const VkCommandBuffer* pCommandBuffers);
+    bool GpuPreCallCreateShaderModule(layer_data* dev_data, const VkShaderModuleCreateInfo* pCreateInfo,
+                                      const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule,
+                                      uint32_t* unique_shader_id, VkShaderModuleCreateInfo* instrumented_create_info,
+                                      std::vector<unsigned int>* instrumented_pgm);
+    bool GpuPreCallCreatePipelineLayout(layer_data* device_data, const VkPipelineLayoutCreateInfo* pCreateInfo,
+                                        const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout,
+                                        std::vector<VkDescriptorSetLayout>* new_layouts,
+                                        VkPipelineLayoutCreateInfo* modified_create_info);
+    void GpuPostCallCreatePipelineLayout(layer_data* device_data, VkResult result);
+    void GpuPostCallQueueSubmit(layer_data* dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits,
+                                VkFence fence);
+    void GpuPreCallValidateCmdWaitEvents(layer_data* dev_data, VkPipelineStageFlags sourceStageMask);
+    std::vector<safe_VkGraphicsPipelineCreateInfo> GpuPreCallRecordCreateGraphicsPipelines(
+        layer_data* dev_data, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo* pCreateInfos,
+        const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, std::vector<std::unique_ptr<PIPELINE_STATE>>& pipe_state);
+    void GpuPostCallRecordCreateGraphicsPipelines(layer_data* dev_data, const uint32_t count,
+                                                  const VkGraphicsPipelineCreateInfo* pCreateInfos,
+                                                  const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+    void GpuPreCallRecordDestroyPipeline(layer_data* dev_data, const VkPipeline pipeline);
+    void GpuAllocateValidationResources(layer_data* dev_data, const VkCommandBuffer cmd_buffer, VkPipelineBindPoint bind_point);
+    void AnalyzeAndReportError(const layer_data* dev_data, GLOBAL_CB_NODE* cb_node, VkQueue queue, uint32_t draw_index,
+                               uint32_t* const debug_output_buffer);
+    void ProcessInstrumentationBuffer(const layer_data* dev_data, VkQueue queue, GLOBAL_CB_NODE* cb_node);
+    void SubmitBarrier(layer_data* dev_data, VkQueue queue);
+    bool GpuInstrumentShader(layer_data* dev_data, const VkShaderModuleCreateInfo* pCreateInfo, std::vector<unsigned int>& new_pgm,
+                             uint32_t* unique_shader_id);
+    void ReportSetupProblem(const layer_data* dev_data, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle,
+                            const char* const specific_message);
+
+    // Buffer Validation Functions
+    template <class OBJECT, class LAYOUT>
+    void SetLayout(layer_data* device_data, OBJECT* pObject, VkImage image, VkImageSubresource range, const LAYOUT& layout);
+    template <class OBJECT, class LAYOUT>
+    void SetLayout(layer_data* device_data, OBJECT* pObject, ImageSubresourcePair imgpair, const LAYOUT& layout,
+                   VkImageAspectFlags aspectMask);
+    // Remove the pending QFO release records from the global set
+    // Note that the type of the handle argument constrained to match Barrier type
+    // The defaulted BarrierRecord argument allows use to declare the type once, but is not intended to be specified by the caller
+    template <typename Barrier, typename BarrierRecord = QFOTransferBarrier<Barrier>>
+    void EraseQFOReleaseBarriers(layer_data* device_data, const typename BarrierRecord::HandleType& handle) {
+        GlobalQFOTransferBarrierMap<Barrier>& global_release_barriers =
+            GetGlobalQFOReleaseBarrierMap(typename BarrierRecord::Tag());
+        global_release_barriers.erase(handle);
+    }
+    bool ValidateCopyImageTransferGranularityRequirements(layer_data* device_data, const GLOBAL_CB_NODE* cb_node,
+                                                          const IMAGE_STATE* src_img, const IMAGE_STATE* dst_img,
+                                                          const VkImageCopy* region, const uint32_t i, const char* function);
+    bool ValidateIdleBuffer(layer_data* device_data, VkBuffer buffer);
+    bool ValidateUsageFlags(const layer_data* device_data, VkFlags actual, VkFlags desired, VkBool32 strict, uint64_t obj_handle,
+                            VulkanObjectType obj_type, const char* msgCode, char const* func_name, char const* usage_str);
+    bool ValidateImageSubresourceRange(const layer_data* device_data, const uint32_t image_mip_count,
+                                       const uint32_t image_layer_count, const VkImageSubresourceRange& subresourceRange,
+                                       const char* cmd_name, const char* param_name, const char* image_layer_count_var_name,
+                                       const uint64_t image_handle, SubresourceRangeErrorCodes errorCodes);
+    void SetImageLayout(layer_data* device_data, GLOBAL_CB_NODE* cb_node, const IMAGE_STATE* image_state,
+                        VkImageSubresourceRange image_subresource_range, const VkImageLayout& layout);
+    void SetImageLayout(layer_data* device_data, GLOBAL_CB_NODE* cb_node, const IMAGE_STATE* image_state,
+                        VkImageSubresourceLayers image_subresource_layers, const VkImageLayout& layout);
+    bool ValidateRenderPassLayoutAgainstFramebufferImageUsage(layer_data* device_data, RenderPassCreateVersion rp_version,
+                                                              VkImageLayout layout, VkImage image, VkImageView image_view,
+                                                              VkFramebuffer framebuffer, VkRenderPass renderpass,
+                                                              uint32_t attachment_index, const char* variable_name);
+    bool ValidateBufferImageCopyData(const debug_report_data* report_data, uint32_t regionCount, const VkBufferImageCopy* pRegions,
+                                     IMAGE_STATE* image_state, const char* function);
+    bool ValidateBufferViewRange(const layer_data* device_data, const BUFFER_STATE* buffer_state,
+                                 const VkBufferViewCreateInfo* pCreateInfo, const VkPhysicalDeviceLimits* device_limits);
+    bool ValidateBufferViewBuffer(const layer_data* device_data, const BUFFER_STATE* buffer_state,
+                                  const VkBufferViewCreateInfo* pCreateInfo);
+
+    bool PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                    VkImage* pImage);
+
+    void PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                   VkImage* pImage, VkResult result);
+
+    void PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator);
+
+    bool PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator);
+
+    bool ValidateImageAttributes(layer_data* device_data, IMAGE_STATE* image_state, VkImageSubresourceRange range);
+
+    bool ValidateClearAttachmentExtent(layer_data* device_data, VkCommandBuffer command_buffer, uint32_t attachment_index,
+                                       FRAMEBUFFER_STATE* framebuffer, uint32_t fb_attachment, const VkRect2D& render_area,
+                                       uint32_t rect_count, const VkClearRect* clear_rects);
+    bool ValidateImageCopyData(const layer_data* device_data, const debug_report_data* report_data, const uint32_t regionCount,
+                               const VkImageCopy* ic_regions, const IMAGE_STATE* src_state, const IMAGE_STATE* dst_state);
+
+    bool VerifyClearImageLayout(layer_data* device_data, GLOBAL_CB_NODE* cb_node, IMAGE_STATE* image_state,
+                                VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char* func_name);
+
+    bool VerifyImageLayout(layer_data const* device_data, GLOBAL_CB_NODE const* cb_node, IMAGE_STATE* image_state,
+                           VkImageSubresourceLayers subLayers, VkImageLayout explicit_layout, VkImageLayout optimal_layout,
+                           const char* caller, const char* layout_invalid_msg_code, const char* layout_mismatch_msg_code,
+                           bool* error);
+
+    bool CheckItgExtent(layer_data* device_data, const GLOBAL_CB_NODE* cb_node, const VkExtent3D* extent, const VkOffset3D* offset,
+                        const VkExtent3D* granularity, const VkExtent3D* subresource_extent, const VkImageType image_type,
+                        const uint32_t i, const char* function, const char* member, const char* vuid);
+
+    bool CheckItgOffset(layer_data* device_data, const GLOBAL_CB_NODE* cb_node, const VkOffset3D* offset,
+                        const VkExtent3D* granularity, const uint32_t i, const char* function, const char* member,
+                        const char* vuid);
+    VkExtent3D GetScaledItg(layer_data* device_data, const GLOBAL_CB_NODE* cb_node, const IMAGE_STATE* img);
+    bool CopyImageMultiplaneValidation(const layer_data* dev_data, VkCommandBuffer command_buffer,
+                                       const IMAGE_STATE* src_image_state, const IMAGE_STATE* dst_image_state,
+                                       const VkImageCopy region);
+
+    void RecordClearImageLayout(layer_data* dev_data, GLOBAL_CB_NODE* cb_node, VkImage image, VkImageSubresourceRange range,
+                                VkImageLayout dest_image_layout);
+
+    bool PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                           const VkClearColorValue* pColor, uint32_t rangeCount,
+                                           const VkImageSubresourceRange* pRanges);
+
+    void PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                         const VkClearColorValue* pColor, uint32_t rangeCount,
+                                         const VkImageSubresourceRange* pRanges);
+
+    bool PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                  const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount,
+                                                  const VkImageSubresourceRange* pRanges);
+
+    void PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
+                                                const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount,
+                                                const VkImageSubresourceRange* pRanges);
+
+    bool FindLayoutVerifyNode(layer_data const* device_data, GLOBAL_CB_NODE const* pCB, ImageSubresourcePair imgpair,
+                              IMAGE_CMD_BUF_LAYOUT_NODE& node, const VkImageAspectFlags aspectMask);
+
+    bool FindLayoutVerifyLayout(layer_data const* device_data, ImageSubresourcePair imgpair, VkImageLayout& layout,
+                                const VkImageAspectFlags aspectMask);
+
+    bool FindCmdBufLayout(layer_data const* device_data, GLOBAL_CB_NODE const* pCB, VkImage image, VkImageSubresource range,
+                          IMAGE_CMD_BUF_LAYOUT_NODE& node);
+
+    bool FindGlobalLayout(layer_data* device_data, ImageSubresourcePair imgpair, VkImageLayout& layout);
+
+    bool FindLayouts(layer_data* device_data, VkImage image, std::vector<VkImageLayout>& layouts);
+
+    bool FindLayout(layer_data* device_data, const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE>& imageLayoutMap,
+                    ImageSubresourcePair imgpair, VkImageLayout& layout);
+
+    bool FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE>& imageLayoutMap, ImageSubresourcePair imgpair,
+                    VkImageLayout& layout, const VkImageAspectFlags aspectMask);
+
+    void SetGlobalLayout(layer_data* device_data, ImageSubresourcePair imgpair, const VkImageLayout& layout);
+
+    void SetImageViewLayout(layer_data* device_data, GLOBAL_CB_NODE* pCB, VkImageView imageView, const VkImageLayout& layout);
+
+    void SetImageViewLayout(layer_data* device_data, GLOBAL_CB_NODE* cb_node, IMAGE_VIEW_STATE* view_state,
+                            const VkImageLayout& layout);
+
+    bool VerifyFramebufferAndRenderPassLayouts(layer_data* dev_data, RenderPassCreateVersion rp_version, GLOBAL_CB_NODE* pCB,
+                                               const VkRenderPassBeginInfo* pRenderPassBegin,
+                                               const FRAMEBUFFER_STATE* framebuffer_state);
+
+    void TransitionAttachmentRefLayout(layer_data* dev_data, GLOBAL_CB_NODE* pCB, FRAMEBUFFER_STATE* pFramebuffer,
+                                       const safe_VkAttachmentReference2KHR& ref);
+
+    void TransitionSubpassLayouts(layer_data*, GLOBAL_CB_NODE*, const RENDER_PASS_STATE*, const int, FRAMEBUFFER_STATE*);
+
+    void TransitionBeginRenderPassLayouts(layer_data*, GLOBAL_CB_NODE*, const RENDER_PASS_STATE*, FRAMEBUFFER_STATE*);
+
+    bool ValidateImageAspectLayout(layer_data* device_data, GLOBAL_CB_NODE const* pCB, const VkImageMemoryBarrier* mem_barrier,
+                                   uint32_t level, uint32_t layer, VkImageAspectFlags aspect);
+
+    void TransitionImageAspectLayout(layer_data* device_data, GLOBAL_CB_NODE* pCB, const VkImageMemoryBarrier* mem_barrier,
+                                     uint32_t level, uint32_t layer, VkImageAspectFlags aspect_mask, VkImageAspectFlags aspect);
+
+    bool ValidateBarrierLayoutToImageUsage(layer_data* device_data, const VkImageMemoryBarrier* img_barrier, bool new_not_old,
+                                           VkImageUsageFlags usage, const char* func_name);
+
+    bool ValidateBarriersToImages(layer_data* device_data, GLOBAL_CB_NODE const* cb_state, uint32_t imageMemoryBarrierCount,
+                                  const VkImageMemoryBarrier* pImageMemoryBarriers, const char* func_name);
+
+    void RecordQueuedQFOTransfers(layer_data* dev_data, GLOBAL_CB_NODE* pCB);
+    void EraseQFOImageRelaseBarriers(layer_data* device_data, const VkImage& image);
+
+    void TransitionImageLayouts(layer_data* device_data, GLOBAL_CB_NODE* cb_state, uint32_t memBarrierCount,
+                                const VkImageMemoryBarrier* pImgMemBarriers);
+
+    void TransitionFinalSubpassLayouts(layer_data* dev_data, GLOBAL_CB_NODE* pCB, const VkRenderPassBeginInfo* pRenderPassBegin,
+                                       FRAMEBUFFER_STATE* framebuffer_state);
+
+    bool PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                     VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                     const VkImageCopy* pRegions);
+
+    bool PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
+                                            const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects);
+
+    bool PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                        const VkImageResolve* pRegions);
+
+    void PreCallRecordCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                      VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                      const VkImageResolve* pRegions);
+
+    bool PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                     VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                     const VkImageBlit* pRegions, VkFilter filter);
+
+    void PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
+                                   VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions,
+                                   VkFilter filter);
+
+    bool ValidateCmdBufImageLayouts(layer_data* device_data, GLOBAL_CB_NODE* pCB,
+                                    std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const& globalImageLayoutMap,
+                                    std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE>& overlayLayoutMap);
+
+    void UpdateCmdBufImageLayouts(layer_data* device_data, GLOBAL_CB_NODE* pCB);
+
+    bool ValidateMaskBitsFromLayouts(layer_data* device_data, VkCommandBuffer cmdBuffer, const VkAccessFlags& accessMask,
+                                     const VkImageLayout& layout, const char* type);
+
+    bool ValidateLayoutVsAttachmentDescription(const debug_report_data* report_data, RenderPassCreateVersion rp_version,
+                                               const VkImageLayout first_layout, const uint32_t attachment,
+                                               const VkAttachmentDescription2KHR& attachment_description);
+
+    bool ValidateLayouts(layer_data* dev_data, RenderPassCreateVersion rp_version, VkDevice device,
+                         const VkRenderPassCreateInfo2KHR* pCreateInfo);
+
+    bool ValidateMapImageLayouts(layer_data* dev_data, VkDevice device, DEVICE_MEM_INFO const* mem_info, VkDeviceSize offset,
+                                 VkDeviceSize end_offset);
+
+    bool ValidateImageUsageFlags(layer_data* dev_data, IMAGE_STATE const* image_state, VkFlags desired, bool strict,
+                                 const char* msgCode, char const* func_name, char const* usage_string);
+
+    bool ValidateImageFormatFeatureFlags(layer_data* dev_data, IMAGE_STATE const* image_state, VkFormatFeatureFlags desired,
+                                         char const* func_name, const char* linear_vuid, const char* optimal_vuid);
+
+    bool ValidateImageSubresourceLayers(layer_data* dev_data, const GLOBAL_CB_NODE* cb_node,
+                                        const VkImageSubresourceLayers* subresource_layers, char const* func_name,
+                                        char const* member, uint32_t i);
+
+    bool ValidateBufferUsageFlags(const layer_data* dev_data, BUFFER_STATE const* buffer_state, VkFlags desired, bool strict,
+                                  const char* msgCode, char const* func_name, char const* usage_string);
+
+    bool PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo,
+                                     const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
+
+    void PostCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                    VkBuffer* pBuffer, VkResult result);
+
+    bool PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo,
+                                         const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
+
+    void PostCallRecordCreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo,
+                                        const VkAllocationCallbacks* pAllocator, VkBufferView* pView, VkResult result);
+
+    bool ValidateImageAspectMask(const layer_data* device_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask,
+                                 const char* func_name, const char* vuid = "VUID-VkImageSubresource-aspectMask-parameter");
+
+    bool ValidateCreateImageViewSubresourceRange(const layer_data* device_data, const IMAGE_STATE* image_state,
+                                                 bool is_imageview_2d_type, const VkImageSubresourceRange& subresourceRange);
+
+    bool ValidateCmdClearColorSubresourceRange(const layer_data* device_data, const IMAGE_STATE* image_state,
+                                               const VkImageSubresourceRange& subresourceRange, const char* param_name);
+
+    bool ValidateCmdClearDepthSubresourceRange(const layer_data* device_data, const IMAGE_STATE* image_state,
+                                               const VkImageSubresourceRange& subresourceRange, const char* param_name);
+
+    bool ValidateImageBarrierSubresourceRange(const layer_data* device_data, const IMAGE_STATE* image_state,
+                                              const VkImageSubresourceRange& subresourceRange, const char* cmd_name,
+                                              const char* param_name);
+
+    bool PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo,
+                                        const VkAllocationCallbacks* pAllocator, VkImageView* pView);
+
+    void PostCallRecordCreateImageView(VkDevice device, const VkImageViewCreateInfo* pCreateInfo,
+                                       const VkAllocationCallbacks* pAllocator, VkImageView* pView, VkResult result);
+
+    bool ValidateCopyBufferImageTransferGranularityRequirements(layer_data* device_data, const GLOBAL_CB_NODE* cb_node,
+                                                                const IMAGE_STATE* img, const VkBufferImageCopy* region,
+                                                                const uint32_t i, const char* function, const char* vuid);
+
+    bool ValidateImageMipLevel(layer_data* device_data, const GLOBAL_CB_NODE* cb_node, const IMAGE_STATE* img, uint32_t mip_level,
+                               const uint32_t i, const char* function, const char* member, const char* vuid);
+
+    bool ValidateImageArrayLayerRange(layer_data* device_data, const GLOBAL_CB_NODE* cb_node, const IMAGE_STATE* img,
+                                      const uint32_t base_layer, const uint32_t layer_count, const uint32_t i, const char* function,
+                                      const char* member, const char* vuid);
+
+    void PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
+                                   VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
+
+    bool PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount,
+                                      const VkBufferCopy* pRegions);
+
+    void PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount,
+                                    const VkBufferCopy* pRegions);
+
+    bool PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator);
+
+    void PreCallRecordDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator);
+
+    bool PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
+
+    void PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
+
+    bool PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator);
+
+    void PreCallRecordDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator);
+
+    bool PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size,
+                                      uint32_t data);
+
+    void PreCallRecordCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size,
+                                    uint32_t data);
+
+    bool PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                             VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+
+    void PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                           VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+
+    bool PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
+                                             VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+
+    void PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
+                                           VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+
+    bool PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource,
+                                                  VkSubresourceLayout* pLayout);
+    bool ValidateCreateImageANDROID(layer_data* device_data, const debug_report_data* report_data,
+                                    const VkImageCreateInfo* create_info);
+    void RecordCreateImageANDROID(const VkImageCreateInfo* create_info, IMAGE_STATE* is_node);
+    bool ValidateCreateImageViewANDROID(layer_data* device_data, const VkImageViewCreateInfo* create_info);
+    bool ValidateGetImageSubresourceLayoutANDROID(layer_data* device_data, const VkImage image);
+    bool ValidateQueueFamilies(layer_data* device_data, uint32_t queue_family_count, const uint32_t* queue_families,
+                               const char* cmd_name, const char* array_parameter_name, const char* unique_error_code,
+                               const char* valid_error_code, bool optional);
+    bool ValidateAllocateMemoryANDROID(layer_data* dev_data, const VkMemoryAllocateInfo* alloc_info);
+    bool ValidateGetImageMemoryRequirements2ANDROID(layer_data* dev_data, const VkImage image);
+    bool ValidateCreateSamplerYcbcrConversionANDROID(const layer_data* dev_data,
+                                                     const VkSamplerYcbcrConversionCreateInfo* create_info);
+    void RecordCreateSamplerYcbcrConversionANDROID(layer_data* dev_data, const VkSamplerYcbcrConversionCreateInfo* create_info,
+                                                   VkSamplerYcbcrConversion ycbcr_conversion);
+    void RecordDestroySamplerYcbcrConversionANDROID(layer_data* dev_data, VkSamplerYcbcrConversion ycbcr_conversion);
+    bool PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                const VkGraphicsPipelineCreateInfo* pCreateInfos,
+                                                const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* cgpl_state);
+    void PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                              const VkGraphicsPipelineCreateInfo* pCreateInfos,
+                                              const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* cgpl_state);
+    void PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                               const VkGraphicsPipelineCreateInfo* pCreateInfos,
+                                               const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result,
+                                               void* cgpl_state);
+    bool PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                               const VkComputePipelineCreateInfo* pCreateInfos,
+                                               const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* pipe_state);
+    void PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                              const VkComputePipelineCreateInfo* pCreateInfos,
+                                              const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result,
+                                              void* pipe_state);
+    bool PreCallValidateCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo,
+                                             const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout);
+    void PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo,
+                                           const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout,
+                                           void* cpl_state);
+    void PostCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo,
+                                            const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout,
+                                            VkResult result);
+    bool PreCallValidateAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo,
+                                               VkDescriptorSet* pDescriptorSets, void* ads_state);
+    void PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo,
+                                              VkDescriptorSet* pDescriptorSets, VkResult result, void* ads_state);
+    bool PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                    const VkRayTracingPipelineCreateInfoNV* pCreateInfos,
+                                                    const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines,
+                                                    void* pipe_state);
+    void PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
+                                                   const VkRayTracingPipelineCreateInfoNV* pCreateInfos,
+                                                   const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result,
+                                                   void* pipe_state);
+    void PostCallRecordCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                      VkInstance* pInstance, VkResult result);
+    bool PreCallValidateCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo,
+                                     const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
+    void PreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo,
+                                   const VkAllocationCallbacks* pAllocator, VkDevice* pDevice,
+                                   std::unique_ptr<safe_VkDeviceCreateInfo>& modified_create_info);
+    void PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo,
+                                    const VkAllocationCallbacks* pAllocator, VkDevice* pDevice, VkResult result);
+    bool PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                        VkDeviceSize dataSize, const void* pData);
+    void PostCallRecordCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                       VkDeviceSize dataSize, const void* pData);
+    void PostCallRecordCreateFence(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                   VkFence* pFence, VkResult result);
+    bool PreCallValidateGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+    void PostCallRecordGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+    void PostCallRecordGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+    bool PreCallValidateCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+                                                     const VkAllocationCallbacks* pAllocator,
+                                                     VkSamplerYcbcrConversion* pYcbcrConversion);
+    void PostCallRecordCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+                                                    const VkAllocationCallbacks* pAllocator,
+                                                    VkSamplerYcbcrConversion* pYcbcrConversion, VkResult result);
+    bool PreCallValidateCreateSamplerYcbcrConversionKHR(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+                                                        const VkAllocationCallbacks* pAllocator,
+                                                        VkSamplerYcbcrConversion* pYcbcrConversion);
+    void PostCallRecordCreateSamplerYcbcrConversionKHR(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+                                                       const VkAllocationCallbacks* pAllocator,
+                                                       VkSamplerYcbcrConversion* pYcbcrConversion, VkResult result);
+    bool PreCallValidateCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+    void PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
+    void PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence,
+                                   VkResult result);
+    bool PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo,
+                                       const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory);
+    void PostCallRecordAllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo,
+                                      const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory, VkResult result);
+    bool PreCallValidateFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll,
+                                      uint64_t timeout);
+    void PostCallRecordWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll,
+                                     uint64_t timeout, VkResult result);
+    bool PreCallValidateGetFenceStatus(VkDevice device, VkFence fence);
+    void PostCallRecordGetFenceStatus(VkDevice device, VkFence fence, VkResult result);
+    bool PreCallValidateQueueWaitIdle(VkQueue queue);
+    void PostCallRecordQueueWaitIdle(VkQueue queue, VkResult result);
+    bool PreCallValidateDeviceWaitIdle(VkDevice device);
+    void PostCallRecordDeviceWaitIdle(VkDevice device, VkResult result);
+    bool PreCallValidateDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
+                                            size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+    void PostCallRecordGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
+                                           size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags,
+                                           VkResult result);
+    bool PreCallValidateBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR* pBindInfos);
+    void PostCallRecordBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR* pBindInfos,
+                                            VkResult result);
+    bool PreCallValidateBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR* pBindInfos);
+    void PostCallRecordBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHR* pBindInfos,
+                                         VkResult result);
+    bool PreCallValidateBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset);
+    void PostCallRecordBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                        VkResult result);
+    void PostCallRecordGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements);
+    void PostCallRecordGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR* pInfo,
+                                                    VkMemoryRequirements2KHR* pMemoryRequirements);
+    void PostCallRecordGetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR* pInfo,
+                                                       VkMemoryRequirements2KHR* pMemoryRequirements);
+    bool PreCallValidateGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo,
+                                                    VkMemoryRequirements2* pMemoryRequirements);
+    bool PreCallValidateGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo,
+                                                       VkMemoryRequirements2* pMemoryRequirements);
+    void PostCallRecordGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);
+    void PostCallRecordGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo,
+                                                   VkMemoryRequirements2* pMemoryRequirements);
+    void PostCallRecordGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo,
+                                                      VkMemoryRequirements2* pMemoryRequirements);
+    void PostCallRecordGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount,
+                                                        VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
+    void PostCallRecordGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
+                                                         uint32_t* pSparseMemoryRequirementCount,
+                                                         VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements);
+    void PostCallRecordGetImageSparseMemoryRequirements2KHR(VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
+                                                            uint32_t* pSparseMemoryRequirementCount,
+                                                            VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements);
+    bool PreCallValidateGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
+                                                                const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+                                                                VkImageFormatProperties2* pImageFormatProperties);
+    bool PreCallValidateGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                   const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+                                                                   VkImageFormatProperties2* pImageFormatProperties);
+    void PreCallRecordDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
+                                            const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
+                                                 const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                              const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                            const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                           const VkCommandBuffer* pCommandBuffers);
+    void PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                         const VkCommandBuffer* pCommandBuffers);
+    bool PreCallValidateCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo,
+                                          const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool);
+    void PostCallRecordCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo,
+                                         const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool, VkResult result);
+    bool PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo,
+                                        const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
+    void PostCallRecordCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo,
+                                       const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool, VkResult result);
+    bool PreCallValidateDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);
+    void PostCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags, VkResult result);
+    bool PreCallValidateResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences);
+    void PostCallRecordResetFences(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkResult result);
+    bool PreCallValidateDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator);
+    void PostCallRecordCreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo,
+                                     const VkAllocationCallbacks* pAllocator, VkSampler* pSampler, VkResult result);
+    bool PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+                                                  const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout);
+    void PostCallRecordCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+                                                 const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout,
+                                                 VkResult result);
+    void PostCallRecordCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo,
+                                            const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool,
+                                            VkResult result);
+    bool PreCallValidateResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);
+    void PostCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags,
+                                           VkResult result);
+    bool PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
+                                           const VkDescriptorSet* pDescriptorSets);
+    void PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
+                                         const VkDescriptorSet* pDescriptorSets);
+    bool PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                             const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount,
+                                             const VkCopyDescriptorSet* pDescriptorCopies);
+    void PreCallRecordUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                           const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount,
+                                           const VkCopyDescriptorSet* pDescriptorCopies);
+    void PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pCreateInfo,
+                                              VkCommandBuffer* pCommandBuffer, VkResult result);
+    bool PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo);
+    void PreCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo);
+    bool PreCallValidateEndCommandBuffer(VkCommandBuffer commandBuffer);
+    void PostCallRecordEndCommandBuffer(VkCommandBuffer commandBuffer, VkResult result);
+    bool PreCallValidateResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);
+    void PostCallRecordResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags, VkResult result);
+    bool PreCallValidateCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
+    void PreCallRecordCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
+    bool PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+                                       const VkViewport* pViewports);
+    void PreCallRecordCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+                                     const VkViewport* pViewports);
+    bool PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
+                                      const VkRect2D* pScissors);
+    void PreCallRecordCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
+                                    const VkRect2D* pScissors);
+    bool PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
+                                                 uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors);
+    void PreCallRecordCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
+                                               uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors);
+    bool PreCallValidateCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout);
+    void PreCallRecordCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout);
+    bool PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                           uint32_t viewportCount,
+                                                           const VkShadingRatePaletteNV* pShadingRatePalettes);
+    void PreCallRecordCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                         uint32_t viewportCount,
+                                                         const VkShadingRatePaletteNV* pShadingRatePalettes);
+    bool PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth);
+    void PreCallRecordCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth);
+    bool PreCallValidateCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
+                                        float depthBiasSlopeFactor);
+    void PreCallRecordCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
+                                      float depthBiasSlopeFactor);
+    bool PreCallValidateCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]);
+    void PreCallRecordCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]);
+    bool PreCallValidateCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);
+    void PreCallRecordCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);
+    bool PreCallValidateCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);
+    void PreCallRecordCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);
+    bool PreCallValidateCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);
+    void PreCallRecordCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);
+    bool PreCallValidateCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);
+    void PreCallRecordCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);
+    bool PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                              VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
+                                              const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount,
+                                              const uint32_t* pDynamicOffsets);
+    void PreCallRecordCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                            VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
+                                            const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount,
+                                            const uint32_t* pDynamicOffsets);
+    bool PreCallValidateCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                                const VkWriteDescriptorSet* pDescriptorWrites);
+    void PreCallRecordCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                              VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                              const VkWriteDescriptorSet* pDescriptorWrites);
+    bool PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                           VkIndexType indexType);
+    void PreCallRecordCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                         VkIndexType indexType);
+    bool PreCallValidateCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
+                                             const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);
+    void PreCallRecordCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
+                                           const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);
+    bool PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex,
+                                uint32_t firstInstance);
+    void PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex,
+                              uint32_t firstInstance);
+    void PostCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex,
+                               uint32_t firstInstance);
+    bool PreCallValidateCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                       uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
+    void PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                     uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
+    void PostCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
+                                      uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
+    bool PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                               uint32_t stride);
+    void PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                             uint32_t stride);
+    void PostCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                              uint32_t stride);
+    bool PreCallValidateCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                       VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                       uint32_t stride);
+    bool PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+    void PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+    void PostCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+    bool PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
+    void PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
+    void PostCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
+    bool PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                        uint32_t stride);
+    void PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                      uint32_t stride);
+    void PostCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                       uint32_t stride);
+    bool PreCallValidateCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+    void PreCallRecordCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+    bool PreCallValidateCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+    void PreCallRecordCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+    bool PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents,
+                                      VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                      uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers,
+                                      uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+                                      uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+    void PreCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents,
+                                    VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                    uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers,
+                                    uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+                                    uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+    void PostCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents,
+                                     VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
+                                     uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers,
+                                     uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+                                     uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+    bool PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
+                                           VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
+                                           uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers,
+                                           uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+                                           uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+    void PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
+                                         VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
+                                         uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers,
+                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+    bool PreCallValidateCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags);
+    void PostCallRecordCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags);
+    bool PreCallValidateCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot);
+    void PostCallRecordCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot);
+    bool PreCallValidateCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                          uint32_t queryCount);
+    void PostCallRecordCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                         uint32_t queryCount);
+    bool PreCallValidateCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                                uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                                VkDeviceSize stride, VkQueryResultFlags flags);
+    void PostCallRecordCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
+                                               uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride,
+                                               VkQueryResultFlags flags);
+    bool PreCallValidateCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
+                                         uint32_t offset, uint32_t size, const void* pValues);
+    bool PreCallValidateCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
+                                          VkQueryPool queryPool, uint32_t slot);
+    void PostCallRecordCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
+                                         VkQueryPool queryPool, uint32_t slot);
+    bool PreCallValidateCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo,
+                                          const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer);
+    void PostCallRecordCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo,
+                                         const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer, VkResult result);
+    bool PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo,
+                                         const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+    void PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo,
+                                        const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass, VkResult result);
+    bool PreCallValidateGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory mem, VkDeviceSize* pCommittedMem);
+    bool PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo,
+                                             const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+    void PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR* pCreateInfo,
+                                            const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass, VkResult result);
+    bool PreCallValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin,
+                                           VkSubpassContents contents);
+    void PreCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin,
+                                         VkSubpassContents contents);
+    bool PreCallValidateCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin,
+                                               const VkSubpassBeginInfoKHR* pSubpassBeginInfo);
+    void PreCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin,
+                                             const VkSubpassBeginInfoKHR* pSubpassBeginInfo);
+    bool PreCallValidateCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
+    void PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
+    bool PreCallValidateCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo,
+                                           const VkSubpassEndInfoKHR* pSubpassEndInfo);
+    void PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfoKHR* pSubpassBeginInfo,
+                                          const VkSubpassEndInfoKHR* pSubpassEndInfo);
+    bool PreCallValidateCmdEndRenderPass(VkCommandBuffer commandBuffer);
+    void PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer);
+    bool PreCallValidateCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo);
+    void PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfoKHR* pSubpassEndInfo);
+    bool PreCallValidateCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
+                                           const VkCommandBuffer* pCommandBuffers);
+    void PreCallRecordCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
+                                         const VkCommandBuffer* pCommandBuffers);
+    bool PreCallValidateMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
+                                  void** ppData);
+    void PostCallRecordMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
+                                 void** ppData, VkResult result);
+    bool PreCallValidateUnmapMemory(VkDevice device, VkDeviceMemory mem);
+    void PreCallRecordUnmapMemory(VkDevice device, VkDeviceMemory mem);
+    bool PreCallValidateFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges);
+    bool PreCallValidateInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
+                                                     const VkMappedMemoryRange* pMemRanges);
+    void PostCallRecordInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges,
+                                                    VkResult result);
+    bool PreCallValidateBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset);
+    void PostCallRecordBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset,
+                                       VkResult result);
+    bool PreCallValidateBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos);
+    void PostCallRecordBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos,
+                                        VkResult result);
+    bool PreCallValidateBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos);
+    void PostCallRecordBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos,
+                                           VkResult result);
+    bool PreCallValidateSetEvent(VkDevice device, VkEvent event);
+    void PreCallRecordSetEvent(VkDevice device, VkEvent event);
+    bool PreCallValidateQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence);
+    void PostCallRecordQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence,
+                                       VkResult result);
+    void PostCallRecordCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo,
+                                       const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore, VkResult result);
+    bool PreCallValidateImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
+    void PostCallRecordImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo,
+                                            VkResult result);
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+    void PostCallRecordImportSemaphoreWin32HandleKHR(VkDevice device,
+                                                     const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo,
+                                                     VkResult result);
+    bool PreCallValidateImportSemaphoreWin32HandleKHR(VkDevice device,
+                                                      const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
+    bool PreCallValidateImportFenceWin32HandleKHR(VkDevice device,
+                                                  const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
+    void PostCallRecordImportFenceWin32HandleKHR(VkDevice device,
+                                                 const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo,
+                                                 VkResult result);
+    void PostCallRecordGetSemaphoreWin32HandleKHR(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+                                                  HANDLE* pHandle, VkResult result);
+    void PostCallRecordGetFenceWin32HandleKHR(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
+                                              HANDLE* pHandle, VkResult result);
+#endif  // VK_USE_PLATFORM_WIN32_KHR
+    bool PreCallValidateImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
+    void PostCallRecordImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo, VkResult result);
+
+    void PostCallRecordGetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd, VkResult result);
+    void PostCallRecordGetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd, VkResult result);
+    void PostCallRecordCreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
+                                   VkEvent* pEvent, VkResult result);
+    bool PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo,
+                                           const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain);
+    void PostCallRecordCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo,
+                                          const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain, VkResult result);
+    void PreCallRecordDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount,
+                                              VkImage* pSwapchainImages);
+    void PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount,
+                                             VkImage* pSwapchainImages, VkResult result);
+    bool PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+    void PostCallRecordQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo, VkResult result);
+    bool PreCallValidateCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
+                                                  const VkSwapchainCreateInfoKHR* pCreateInfos,
+                                                  const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains);
+    void PostCallRecordCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
+                                                 const VkSwapchainCreateInfoKHR* pCreateInfos,
+                                                 const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains,
+                                                 VkResult result);
+    bool PreCallValidateAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore,
+                                            VkFence fence, uint32_t* pImageIndex);
+    bool PreCallValidateAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
+    void PostCallRecordAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore,
+                                           VkFence fence, uint32_t* pImageIndex, VkResult result);
+    void PostCallRecordAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex,
+                                            VkResult result);
+    void PostCallRecordEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount,
+                                                VkPhysicalDevice* pPhysicalDevices, VkResult result);
+    bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount,
+                                                               VkQueueFamilyProperties* pQueueFamilyProperties);
+    void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount,
+                                                              VkQueueFamilyProperties* pQueueFamilyProperties);
+    bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
+                                                                uint32_t* pQueueFamilyPropertyCount,
+                                                                VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+    void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount,
+                                                               VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+    bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                   uint32_t* pQueueFamilyPropertyCount,
+                                                                   VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+    void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                  uint32_t* pQueueFamilyPropertyCount,
+                                                                  VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+    bool PreCallValidateDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordValidateDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
+    void PostCallRecordGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                               VkSurfaceCapabilitiesKHR* pSurfaceCapabilities, VkResult result);
+    void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
+                                                                const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+                                                                VkSurfaceCapabilities2KHR* pSurfaceCapabilities, VkResult result);
+    void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                                VkSurfaceCapabilities2EXT* pSurfaceCapabilities, VkResult result);
+    bool PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                           VkSurfaceKHR surface, VkBool32* pSupported);
+    void PostCallRecordGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                          VkSurfaceKHR surface, VkBool32* pSupported, VkResult result);
+    void PostCallRecordGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                               uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes,
+                                                               VkResult result);
+    bool PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                           uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);
+    void PostCallRecordGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
+                                                          uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats,
+                                                          VkResult result);
+    void PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
+                                                           const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
+                                                           uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats,
+                                                           VkResult result);
+    void PostCallRecordCreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
+                                                    const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface,
+                                                    VkResult result);
+    void PreCallRecordQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo);
+    void PostCallRecordQueueEndDebugUtilsLabelEXT(VkQueue queue);
+    void PreCallRecordQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo);
+    void PreCallRecordCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo);
+    void PostCallRecordCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer);
+    void PreCallRecordCmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo);
+    void PostCallRecordCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
+                                                    const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger,
+                                                    VkResult result);
+    void PostCallRecordDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                     const VkAllocationCallbacks* pAllocator);
+    void PostCallRecordDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
+                                                     const VkAllocationCallbacks* pAllocator);
+    void PostCallRecordEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount,
+                                                     VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties,
+                                                     VkResult result);
+    void PostCallRecordEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount,
+                                                        VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties,
+                                                        VkResult result);
+    bool PreCallValidateCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+                                                       const VkAllocationCallbacks* pAllocator,
+                                                       VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
+    void PostCallRecordCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+                                                      const VkAllocationCallbacks* pAllocator,
+                                                      VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate, VkResult result);
+    bool PreCallValidateCreateDescriptorUpdateTemplateKHR(VkDevice device,
+                                                          const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+                                                          const VkAllocationCallbacks* pAllocator,
+                                                          VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
+    void PostCallRecordCreateDescriptorUpdateTemplateKHR(VkDevice device,
+                                                         const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+                                                         const VkAllocationCallbacks* pAllocator,
+                                                         VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate, VkResult result);
+    void PreCallRecordDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                      const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordDestroyDescriptorUpdateTemplateKHR(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                         const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
+                                                        VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+    void PreCallRecordUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
+                                                      VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+    bool PreCallValidateUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
+                                                           VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                           const void* pData);
+    void PreCallRecordUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
+                                                         VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
+
+    bool PreCallValidateCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
+                                                            VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                            VkPipelineLayout layout, uint32_t set, const void* pData);
+    void PreCallRecordCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
+                                                          VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                          VkPipelineLayout layout, uint32_t set, const void* pData);
+    void PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount,
+                                                                  VkDisplayPlanePropertiesKHR* pProperties, VkResult result);
+    void PostCallRecordGetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount,
+                                                                   VkDisplayPlaneProperties2KHR* pProperties, VkResult result);
+    bool PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                            uint32_t* pDisplayCount, VkDisplayKHR* pDisplays);
+    bool PreCallValidateGetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex,
+                                                       VkDisplayPlaneCapabilitiesKHR* pCapabilities);
+    bool PreCallValidateGetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
+                                                        const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo,
+                                                        VkDisplayPlaneCapabilities2KHR* pCapabilities);
+    bool PreCallValidateCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer);
+    bool PreCallValidateCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle,
+                                                  uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles);
+    bool PreCallValidateCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,
+                                                 const VkSampleLocationsInfoEXT* pSampleLocationsInfo);
+    bool PreCallValidateCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                uint32_t stride);
+    void PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                              VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                              uint32_t stride);
+    void PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                     VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                     uint32_t stride);
+    bool PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask);
+    void PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask);
+    bool PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                   uint32_t drawCount, uint32_t stride);
+    void PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                 uint32_t drawCount, uint32_t stride);
+    bool PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                        VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                        uint32_t stride);
+    void PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                      VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
+                                                      uint32_t stride);
+    void PostCallRecordDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion,
+                                                     const VkAllocationCallbacks* pAllocator);
+    void PreCallRecordGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
+                                                  VkPhysicalDeviceProperties* pPhysicalDeviceProperties);
+    void PostCallRecordDestroySamplerYcbcrConversionKHR(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion,
+                                                        const VkAllocationCallbacks* pAllocator);
+    bool PreCallValidateGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfoEXT* pInfo);
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+    bool PreCallValidateGetAndroidHardwareBufferProperties(VkDevice device, const struct AHardwareBuffer* buffer,
+                                                           VkAndroidHardwareBufferPropertiesANDROID* pProperties);
+    void PostCallRecordGetAndroidHardwareBufferProperties(VkDevice device, const struct AHardwareBuffer* buffer,
+                                                          VkAndroidHardwareBufferPropertiesANDROID* pProperties, VkResult result);
+    bool PreCallValidateGetMemoryAndroidHardwareBuffer(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
+                                                       struct AHardwareBuffer** pBuffer);
+    void PostCallRecordCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
+                                               const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+#ifdef VK_USE_PLATFORM_IOS_MVK
+    void PostCallRecordCreateIOSSurfaceMVK(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
+                                           const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_IOS_MVK
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+    void PostCallRecordCreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
+                                             const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_MACOS_MVK
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+    bool PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                                       struct wl_display* display);
+    void PostCallRecordCreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
+                                               const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_WAYLAND_KHR
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+    bool PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
+    void PostCallRecordCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
+                                             const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_WIN32_KHR
+#ifdef VK_USE_PLATFORM_XCB_KHR
+    bool PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                                   xcb_connection_t* connection, xcb_visualid_t visual_id);
+    void PostCallRecordCreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
+                                           const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_XCB_KHR
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+    bool PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
+                                                                    Display* dpy, VisualID visualID);
+    void PostCallRecordCreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
+                                            const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface, VkResult result);
+#endif  // VK_USE_PLATFORM_XLIB_KHR
+
+};  // Class CoreChecks
diff --git a/layers/core_validation_error_enums.h b/layers/core_validation_error_enums.h
index 1f214bf..0b546fe 100644
--- a/layers/core_validation_error_enums.h
+++ b/layers/core_validation_error_enums.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
  * Author: Chris Forbes <chrisf@ijw.co.nz>
  * Author: Mark Lobodzinski <mark@lunarg.com>
  * Author: Dave Houlton <daveh@lunarg.com>
+ * Author: John Zulauf <jzulauf@lunarg.com>
  */
 #ifndef CORE_VALIDATION_ERROR_ENUMS_H_
 #define CORE_VALIDATION_ERROR_ENUMS_H_
@@ -63,7 +64,6 @@
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidCommandBuffer = "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidCommandBufferSimultaneousUse = "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBufferSimultaneousUse";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidDescriptorSet = "UNASSIGNED-CoreValidation-DrawState-InvalidDescriptorSet";
-static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidDynamicOffsetCount = "UNASSIGNED-CoreValidation-DrawState-InvalidDynamicOffsetCount";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidEvent = "UNASSIGNED-CoreValidation-DrawState-InvalidEvent";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidExtents = "UNASSIGNED-CoreValidation-DrawState-InvalidExtents";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidFeature = "UNASSIGNED-CoreValidation-DrawState-InvalidFeature";
@@ -89,7 +89,6 @@
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_OutOfMemory = "UNASSIGNED-CoreValidation-DrawState-OutOfMemory";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_PipelineLayoutsIncompatible = "UNASSIGNED-CoreValidation-DrawState-PipelineLayoutsIncompatible";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_QueueForwardProgress = "UNASSIGNED-CoreValidation-DrawState-QueueForwardProgress";
-static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainAlreadyExists = "UNASSIGNED-CoreValidation-DrawState-SwapchainAlreadyExists";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainCreateBeforeQuery = "UNASSIGNED-CoreValidation-DrawState-SwapchainCreateBeforeQuery";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainImageNotAcquired = "UNASSIGNED-CoreValidation-DrawState-SwapchainImageNotAcquired";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainImagesNotFound = "UNASSIGNED-CoreValidation-DrawState-SwapchainImagesNotFound";
@@ -98,7 +97,6 @@
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainReplaced = "UNASSIGNED-CoreValidation-DrawState-SwapchainReplaced";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainTooManyImages = "UNASSIGNED-CoreValidation-DrawState-SwapchainTooManyImages";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainUnsupportedQueue = "UNASSIGNED-CoreValidation-DrawState-SwapchainUnsupportedQueue";
-static const char DECORATE_UNUSED *kVUID_Core_DrawState_SwapchainWrongSurface = "UNASSIGNED-CoreValidation-DrawState-SwapchainWrongSurface";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_ViewportScissorMismatch = "UNASSIGNED-CoreValidation-DrawState-ViewportScissorMismatch";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_VtxIndexOutOfBounds = "UNASSIGNED-CoreValidation-DrawState-VtxIndexOutOfBounds";
 static const char DECORATE_UNUSED *kVUID_Core_DrawState_InvalidVtxAttributeAlignment = "UNASSIGNED-CoreValidation-DrawState-InvalidVtxAttributeAlignment";
@@ -169,6 +167,7 @@
 
 static const char DECORATE_UNUSED *kVUID_Core_Shader_DescriptorNotAccessibleFromStage = "UNASSIGNED-CoreValidation-Shader-DescriptorNotAccessibleFromStage";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_DescriptorTypeMismatch = "UNASSIGNED-CoreValidation-Shader-DescriptorTypeMismatch";
+static const char DECORATE_UNUSED *kVUID_Core_Shader_ExceedDeviceLimit = "UNASSIGNED-CoreValidation-Shader-ExceedDeviceLimit";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_FeatureNotEnabled = "UNASSIGNED-CoreValidation-Shader-FeatureNotEnabled";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_InconsistentSpirv = "UNASSIGNED-CoreValidation-Shader-InconsistentSpirv";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_InconsistentVi = "UNASSIGNED-CoreValidation-Shader-InconsistentVi";
@@ -182,6 +181,7 @@
 static const char DECORATE_UNUSED *kVUID_Core_Shader_PushConstantOutOfRange = "UNASSIGNED-CoreValidation-Shader-PushConstantOutOfRange";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_MissingPointSizeBuiltIn = "UNASSIGNED-CoreValidation-Shader-PointSizeMissing";
 static const char DECORATE_UNUSED *kVUID_Core_Shader_PointSizeBuiltInOverSpecified = "UNASSIGNED-CoreValidation-Shader-PointSizeOverSpecified";
+static const char DECORATE_UNUSED *kVUID_Core_Shader_NoAlphaAtLocation0WithAlphaToCoverage = "UNASSIGNED-CoreValidation-Shader-NoAlphaAtLocation0WithAlphaToCoverage";
 // Previously defined but unused - uncomment as needed
 //static const char DECORATE_UNUSED *kVUID_Core_Shader_BadCapability = "UNASSIGNED-CoreValidation-Shader-BadCapability";
 //static const char DECORATE_UNUSED *kVUID_Core_Shader_BadSpecialization = "UNASSIGNED-CoreValidation-Shader-BadSpecialization";
@@ -228,6 +228,10 @@
 static const char DECORATE_UNUSED *kVUID_Core_Image_InvalidFormatLimitsViolation = "UNASSIGNED-CoreValidation-Image-InvalidFormatLimitsViolation";
 static const char DECORATE_UNUSED *kVUID_Core_Image_ZeroAreaSubregion = "UNASSIGNED-CoreValidation-Image-ZeroAreaSubregion";
 
+static const char DECORATE_UNUSED *kVUID_Core_PushDescriptorUpdate_TemplateType = "UNASSIGNED-CoreValidation-vkCmdPushDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-templateType";
+static const char DECORATE_UNUSED *kVUID_Core_PushDescriptorUpdate_Template_SetMismatched = "UNASSIGNED-CoreValidation-vkCmdPushDescriptorSetWithTemplateKHR-set";
+static const char DECORATE_UNUSED *kVUID_Core_PushDescriptorUpdate_Template_LayoutMismatched = "UNASSIGNED-CoreValidation-vkCmdPushDescriptorSetWithTemplateKHR-layout";
+
 // clang-format on
 
 #undef DECORATE_UNUSED
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index d90f503..bed42da 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
  * Author: Tobin Ehlis <tobine@google.com>
  * Author: Chris Forbes <chrisf@ijw.co.nz>
  * Author: Mark Lobodzinski <mark@lunarg.com>
+ * Author: Dave Houlton <daveh@lunarg.com>
  */
 #ifndef CORE_VALIDATION_TYPES_H_
 #define CORE_VALIDATION_TYPES_H_
@@ -29,10 +30,14 @@
 #include "vk_layer_logging.h"
 #include "vk_object_types.h"
 #include "vk_extension_helper.h"
+#include "vk_typemap_helper.h"
 #include "convert_to_renderpass2.h"
 #include <atomic>
 #include <functional>
+#include <list>
 #include <map>
+#include <memory>
+#include <set>
 #include <string.h>
 #include <unordered_map>
 #include <unordered_set>
@@ -40,6 +45,14 @@
 #include <memory>
 #include <list>
 
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+#include "android_ndk_types.h"
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+class CoreChecks;
+typedef CoreChecks layer_data;
+typedef CoreChecks instance_layer_data;
+
 // Fwd declarations -- including descriptor_set.h creates an ugly include loop
 namespace cvdescriptorset {
 class DescriptorSetLayoutDef;
@@ -83,7 +96,7 @@
 }
 
 template <typename Barrier, bool assume_transfer = false>
-static bool IsReleaseOp(const COMMAND_POOL_NODE *pool, const Barrier *barrier) {
+static bool TempIsReleaseOp(const COMMAND_POOL_NODE *pool, const Barrier *barrier) {
     return (assume_transfer || IsTransferOp(barrier)) && (pool->queueFamilyIndex == barrier->srcQueueFamilyIndex);
 }
 
@@ -111,12 +124,6 @@
 };
 }  // namespace std
 
-class PHYS_DEV_PROPERTIES_NODE {
-   public:
-    VkPhysicalDeviceProperties properties;
-    std::vector<VkQueueFamilyProperties> queue_family_properties;
-};
-
 // Flags describing requirements imposed by the pipeline on a descriptor. These
 // can't be checked at pipeline creation time as they depend on the Image or
 // ImageView bound.
@@ -272,8 +279,12 @@
 struct SAMPLER_STATE : public BASE_NODE {
     VkSampler sampler;
     VkSamplerCreateInfo createInfo;
+    VkSamplerYcbcrConversion samplerConversion = VK_NULL_HANDLE;
 
-    SAMPLER_STATE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci){};
+    SAMPLER_STATE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci) {
+        auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(pci->pNext);
+        if (conversionInfo) samplerConversion = conversionInfo->conversion;
+    }
 };
 
 class IMAGE_STATE : public BINDABLE {
@@ -287,6 +298,9 @@
     bool get_sparse_reqs_called;  // Track if GetImageSparseMemoryRequirements() has been called for this image
     bool sparse_metadata_required;  // Track if sparse metadata aspect is required for this image
     bool sparse_metadata_bound;     // Track if sparse metadata aspect is bound to this image
+    bool imported_ahb;              // True if image was imported from an Android Hardware Buffer
+    bool has_ahb_format;            // True if image was created with an external Android format
+    uint64_t ahb_format;            // External Android format, if provided
     std::vector<VkSparseImageMemoryRequirements> sparse_requirements;
     IMAGE_STATE(VkImage img, const VkImageCreateInfo *pCreateInfo)
         : image(img),
@@ -298,6 +312,9 @@
           get_sparse_reqs_called(false),
           sparse_metadata_required(false),
           sparse_metadata_bound(false),
+          imported_ahb(false),
+          has_ahb_format(false),
+          ahb_format(0),
           sparse_requirements{} {
         if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
             uint32_t *pQueueFamilyIndices = new uint32_t[createInfo.queueFamilyIndexCount];
@@ -326,7 +343,12 @@
    public:
     VkImageView image_view;
     VkImageViewCreateInfo create_info;
-    IMAGE_VIEW_STATE(VkImageView iv, const VkImageViewCreateInfo *ci) : image_view(iv), create_info(*ci){};
+    VkSamplerYcbcrConversion samplerConversion;  // Handle of the ycbcr sampler conversion the image was created with, if any
+    IMAGE_VIEW_STATE(VkImageView iv, const VkImageViewCreateInfo *ci)
+        : image_view(iv), create_info(*ci), samplerConversion(VK_NULL_HANDLE) {
+        auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
+        if (conversionInfo) samplerConversion = conversionInfo->conversion;
+    };
     IMAGE_VIEW_STATE(const IMAGE_VIEW_STATE &rh_obj) = delete;
 };
 
@@ -355,6 +377,8 @@
     bool is_dedicated;
     VkBuffer dedicated_buffer;
     VkImage dedicated_image;
+    bool is_export;
+    VkExternalMemoryHandleTypeFlags export_handle_type_flags;
     std::unordered_set<VK_OBJECT> obj_bindings;               // objects bound to this memory
     std::unordered_map<uint64_t, MEMORY_RANGE> bound_ranges;  // Map of object to its binding range
     // Convenience vectors image/buff handles to speed up iterating over images or buffers independently
@@ -375,6 +399,8 @@
           is_dedicated(false),
           dedicated_buffer(VK_NULL_HANDLE),
           dedicated_image(VK_NULL_HANDLE),
+          is_export(false),
+          export_handle_type_flags(0),
           mem_range{},
           shadow_copy_base(0),
           shadow_copy(0),
@@ -387,7 +413,7 @@
     safe_VkSwapchainCreateInfoKHR createInfo;
     VkSwapchainKHR swapchain;
     std::vector<VkImage> images;
-    bool replaced = false;
+    bool retired = false;
     bool shared_presentable = false;
     CALL_STATE vkGetSwapchainImagesKHRState = UNCALLED;
     uint32_t get_swapchain_image_count = 0;
@@ -530,14 +556,6 @@
     // clang-format on
 };
 
-struct TEMPLATE_STATE {
-    VkDescriptorUpdateTemplateKHR desc_update_template;
-    safe_VkDescriptorUpdateTemplateCreateInfo create_info;
-
-    TEMPLATE_STATE(VkDescriptorUpdateTemplateKHR update_template, safe_VkDescriptorUpdateTemplateCreateInfo *pCreateInfo)
-        : desc_update_template(update_template), create_info(*pCreateInfo) {}
-};
-
 struct QueryObject {
     VkQueryPool pool;
     uint32_t index;
@@ -636,6 +654,18 @@
     }
 };
 
+static inline bool CompatForSet(uint32_t set, const std::vector<PipelineLayoutCompatId> &a,
+                                const std::vector<PipelineLayoutCompatId> &b) {
+    bool result = (set < a.size()) && (set < b.size()) && (a[set] == b[set]);
+    return result;
+}
+
+static inline bool CompatForSet(uint32_t set, const PIPELINE_LAYOUT_NODE *a, const PIPELINE_LAYOUT_NODE *b) {
+    // Intentionally have a result variable to simplify debugging
+    bool result = a && b && CompatForSet(set, a->compat_for_set, b->compat_for_set);
+    return result;
+}
+
 class PIPELINE_STATE : public BASE_NODE {
    public:
     VkPipeline pipeline;
@@ -643,7 +673,7 @@
     // Hold shared ptr to RP in case RP itself is destroyed
     std::shared_ptr<RENDER_PASS_STATE> rp_state;
     safe_VkComputePipelineCreateInfo computePipelineCI;
-    safe_VkRaytracingPipelineCreateInfoNVX raytracingPipelineCI;
+    safe_VkRayTracingPipelineCreateInfoNV raytracingPipelineCI;
     // Flag of which shader stages are active for this pipeline
     uint32_t active_shaders;
     uint32_t duplicate_shaders;
@@ -746,7 +776,7 @@
                 break;
         }
     }
-    void initRaytracingPipelineNVX(const VkRaytracingPipelineCreateInfoNVX *pCreateInfo) {
+    void initRayTracingPipelineNV(const VkRayTracingPipelineCreateInfoNV *pCreateInfo) {
         raytracingPipelineCI.initialize(pCreateInfo);
         // Make sure gfx and compute pipeline is null
         VkGraphicsPipelineCreateInfo emptyGraphicsCI = {};
@@ -754,23 +784,23 @@
         computePipelineCI.initialize(&emptyComputeCI);
         graphicsPipelineCI.initialize(&emptyGraphicsCI, false, false);
         switch (raytracingPipelineCI.pStages->stage) {
-            case VK_SHADER_STAGE_RAYGEN_BIT_NVX:
-                this->active_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_NVX;
+            case VK_SHADER_STAGE_RAYGEN_BIT_NV:
+                this->active_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_NV;
                 break;
-            case VK_SHADER_STAGE_ANY_HIT_BIT_NVX:
-                this->active_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_NVX;
+            case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
+                this->active_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_NV;
                 break;
-            case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX:
-                this->active_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX;
+            case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
+                this->active_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
                 break;
-            case VK_SHADER_STAGE_MISS_BIT_NVX:
-                this->active_shaders = VK_SHADER_STAGE_MISS_BIT_NVX;
+            case VK_SHADER_STAGE_MISS_BIT_NV:
+                this->active_shaders = VK_SHADER_STAGE_MISS_BIT_NV;
                 break;
-            case VK_SHADER_STAGE_INTERSECTION_BIT_NVX:
-                this->active_shaders = VK_SHADER_STAGE_INTERSECTION_BIT_NVX;
+            case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
+                this->active_shaders = VK_SHADER_STAGE_INTERSECTION_BIT_NV;
                 break;
-            case VK_SHADER_STAGE_CALLABLE_BIT_NVX:
-                this->active_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_NVX;
+            case VK_SHADER_STAGE_CALLABLE_BIT_NV:
+                this->active_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_NV;
                 break;
             default:
                 // TODO : Flag error
@@ -930,6 +960,20 @@
     QFOTransferCBScoreboard<Barrier> release;
 };
 
+struct GpuDeviceMemoryBlock {
+    VkBuffer buffer;
+    VkDeviceMemory memory;
+    uint32_t offset;
+};
+
+struct GpuBufferInfo {
+    GpuDeviceMemoryBlock mem_block;
+    VkDescriptorSet desc_set;
+    VkDescriptorPool desc_pool;
+    GpuBufferInfo(GpuDeviceMemoryBlock mem_block, VkDescriptorSet desc_set, VkDescriptorPool desc_pool)
+        : mem_block(mem_block), desc_set(desc_set), desc_pool(desc_pool){};
+};
+
 // Cmd Buffer Wrapper Struct - TODO : This desperately needs its own class
 struct GLOBAL_CB_NODE : public BASE_NODE {
     VkCommandBuffer commandBuffer;
@@ -996,13 +1040,15 @@
     std::unordered_set<cvdescriptorset::DescriptorSet *> validated_descriptor_sets;
     // Contents valid only after an index buffer is bound (CBSTATUS_INDEX_BUFFER_BOUND set)
     IndexBufferBinding index_buffer_binding;
+    // GPU Validation data
+    std::vector<GpuBufferInfo> gpu_buffer_list;
 };
 
-static QFOTransferBarrierSets<VkImageMemoryBarrier> &GetQFOBarrierSets(
+static inline QFOTransferBarrierSets<VkImageMemoryBarrier> &GetQFOBarrierSets(
     GLOBAL_CB_NODE *cb, const QFOTransferBarrier<VkImageMemoryBarrier>::Tag &type_tag) {
     return cb->qfo_transfer_image_barriers;
 }
-static QFOTransferBarrierSets<VkBufferMemoryBarrier> &GetQFOBarrierSets(
+static inline QFOTransferBarrierSets<VkBufferMemoryBarrier> &GetQFOBarrierSets(
     GLOBAL_CB_NODE *cb, const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag &type_tag) {
     return cb->qfo_transfer_buffer_barriers;
 }
@@ -1035,44 +1081,6 @@
     VkFormat format;
 };
 
-// CHECK_DISABLED struct is a container for bools that can block validation checks from being performed.
-// The end goal is to have all checks guarded by a bool. The bools are all "false" by default meaning that all checks
-// are enabled. At CreateInstance time, the user can use the VK_EXT_validation_flags extension to pass in enum values
-// of VkValidationCheckEXT that will selectively disable checks.
-struct CHECK_DISABLED {
-    bool command_buffer_state;
-    bool create_descriptor_set_layout;
-    bool destroy_buffer_view;       // Skip validation at DestroyBufferView time
-    bool destroy_image_view;        // Skip validation at DestroyImageView time
-    bool destroy_pipeline;          // Skip validation at DestroyPipeline time
-    bool destroy_descriptor_pool;   // Skip validation at DestroyDescriptorPool time
-    bool destroy_framebuffer;       // Skip validation at DestroyFramebuffer time
-    bool destroy_renderpass;        // Skip validation at DestroyRenderpass time
-    bool destroy_image;             // Skip validation at DestroyImage time
-    bool destroy_sampler;           // Skip validation at DestroySampler time
-    bool destroy_command_pool;      // Skip validation at DestroyCommandPool time
-    bool destroy_event;             // Skip validation at DestroyEvent time
-    bool free_memory;               // Skip validation at FreeMemory time
-    bool object_in_use;             // Skip all object in_use checking
-    bool idle_descriptor_set;       // Skip check to verify that descriptor set is no in-use
-    bool push_constant_range;       // Skip push constant range checks
-    bool free_descriptor_sets;      // Skip validation prior to vkFreeDescriptorSets()
-    bool allocate_descriptor_sets;  // Skip validation prior to vkAllocateDescriptorSets()
-    bool update_descriptor_sets;    // Skip validation prior to vkUpdateDescriptorSets()
-    bool wait_for_fences;
-    bool get_fence_state;
-    bool queue_wait_idle;
-    bool device_wait_idle;
-    bool destroy_fence;
-    bool destroy_semaphore;
-    bool destroy_query_pool;
-    bool get_query_pool_results;
-    bool destroy_buffer;
-    bool shader_validation;  // Skip validation for shaders
-
-    void SetAll(bool value) { std::fill(&command_buffer_state, &shader_validation + 1, value); }
-};
-
 struct MT_FB_ATTACHMENT_INFO {
     IMAGE_VIEW_STATE *view_state;
     VkImage image;
@@ -1104,86 +1112,43 @@
     VkPhysicalDeviceShadingRateImageFeaturesNV shading_rate_image;
     VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader;
     VkPhysicalDeviceInlineUniformBlockFeaturesEXT inline_uniform_block;
+    VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback_features;
+    VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vtx_attrib_divisor_features;
+    VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalar_block_layout_features;
+    VkPhysicalDeviceBufferAddressFeaturesEXT buffer_address;
 };
 
 enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
 
-// Fwd declarations of layer_data and helpers to look-up/validate state from layer_data maps
-namespace core_validation {
-struct layer_data;
-cvdescriptorset::DescriptorSet *GetSetNode(const layer_data *, VkDescriptorSet);
+class GpuDeviceMemoryManager;
+class GpuDescriptorSetManager;
+struct ShaderTracker {
+    VkPipeline pipeline;
+    VkShaderModule shader_module;
+    std::vector<unsigned int> pgm;
+};
+struct GpuValidationState {
+    bool aborted;
+    bool reserve_binding_slot;
+    VkDescriptorSetLayout debug_desc_layout;
+    VkDescriptorSetLayout dummy_desc_layout;
+    uint32_t adjusted_max_desc_sets;
+    uint32_t desc_set_bind_index;
+    uint32_t unique_shader_module_id;
+    std::unordered_map<uint32_t, ShaderTracker> shader_map;
+    std::unique_ptr<GpuDeviceMemoryManager> memory_manager;
+    std::unique_ptr<GpuDescriptorSetManager> desc_set_manager;
+    VkCommandPool barrier_command_pool;
+    VkCommandBuffer barrier_command_buffer;
+};
+
+enum BarrierOperationsType {
+    kAllAcquire,  // All Barrier operations are "ownership acquire" operations
+    kAllRelease,  // All Barrier operations are "ownership release" operations
+    kGeneral,     // Either no ownership operations or a mix of ownership operation types and/or non-ownership operations
+};
+
 std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> const GetDescriptorSetLayout(layer_data const *, VkDescriptorSetLayout);
-DESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *, const VkDescriptorPool);
-BUFFER_STATE *GetBufferState(const layer_data *, VkBuffer);
-IMAGE_STATE *GetImageState(const layer_data *, VkImage);
-DEVICE_MEM_INFO *GetMemObjInfo(const layer_data *, VkDeviceMemory);
-BUFFER_VIEW_STATE *GetBufferViewState(const layer_data *, VkBufferView);
-SAMPLER_STATE *GetSamplerState(const layer_data *, VkSampler);
-IMAGE_VIEW_STATE *GetAttachmentImageViewState(layer_data *dev_data, FRAMEBUFFER_STATE *framebuffer, uint32_t index);
-IMAGE_VIEW_STATE *GetImageViewState(const layer_data *, VkImageView);
-SWAPCHAIN_NODE *GetSwapchainNode(const layer_data *, VkSwapchainKHR);
-GLOBAL_CB_NODE *GetCBNode(layer_data const *my_data, const VkCommandBuffer cb);
-RENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass);
-std::shared_ptr<RENDER_PASS_STATE> GetRenderPassStateSharedPtr(layer_data const *dev_data, VkRenderPass renderpass);
-FRAMEBUFFER_STATE *GetFramebufferState(const layer_data *my_data, VkFramebuffer framebuffer);
-COMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool);
-shader_module const *GetShaderModuleState(layer_data const *dev_data, VkShaderModule module);
-const PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data);
-const DeviceFeatures *GetEnabledFeatures(const layer_data *device_data);
-const DeviceExtensions *GetEnabledExtensions(const layer_data *device_data);
-
-void InvalidateCommandBuffers(const layer_data *, std::unordered_set<GLOBAL_CB_NODE *> const &, VK_OBJECT);
-bool ValidateMemoryIsBoundToBuffer(const layer_data *, const BUFFER_STATE *, const char *, const std::string &);
-bool ValidateMemoryIsBoundToImage(const layer_data *, const IMAGE_STATE *, const char *, const std::string &);
-void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *, SAMPLER_STATE *);
-void AddCommandBufferBindingImage(const layer_data *, GLOBAL_CB_NODE *, IMAGE_STATE *);
-void AddCommandBufferBindingImageView(const layer_data *, GLOBAL_CB_NODE *, IMAGE_VIEW_STATE *);
-void AddCommandBufferBindingBuffer(const layer_data *, GLOBAL_CB_NODE *, BUFFER_STATE *);
-void AddCommandBufferBindingBufferView(const layer_data *, GLOBAL_CB_NODE *, BUFFER_VIEW_STATE *);
-bool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct, const char *caller_name,
-                            const std::string &error_code);
-void InvalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj);
-void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info);
-void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info);
-void ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type);
-bool ValidateCmdQueueFlags(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags flags,
-                           const std::string &error_code);
-bool ValidateCmd(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name);
-bool InsideRenderPass(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const char *apiName, const std::string &msgCode);
-void SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid);
-bool OutsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName, const std::string &msgCode);
-void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node);
-void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout);
-bool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName);
-bool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
-                              const char *location, const std::string &msgCode);
-bool RangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end);
-bool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName);
-void SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid);
-bool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type);
-bool ValidateCmd(layer_data *dev_data, const GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name);
-
-// Prototypes for layer_data accessor functions.  These should be in their own header file at some point
-VkFormatProperties GetFormatProperties(const core_validation::layer_data *device_data, const VkFormat format);
-VkResult GetImageFormatProperties(core_validation::layer_data *device_data, const VkImageCreateInfo *image_ci,
-                                  VkImageFormatProperties *image_format_properties);
-const debug_report_data *GetReportData(const layer_data *);
-const VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(const layer_data *);
-const CHECK_DISABLED *GetDisables(layer_data *);
-std::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *);
-std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(layer_data *);
-std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *);
-std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *);
-std::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data);
-std::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data);
-std::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data);
-const DeviceExtensions *GetDeviceExtensions(const layer_data *);
-uint32_t GetApiVersion(const layer_data *);
-
-GlobalQFOTransferBarrierMap<VkImageMemoryBarrier> &GetGlobalQFOReleaseBarrierMap(
-    layer_data *dev_data, const QFOTransferBarrier<VkImageMemoryBarrier>::Tag &type_tag);
-GlobalQFOTransferBarrierMap<VkBufferMemoryBarrier> &GetGlobalQFOReleaseBarrierMap(
-    layer_data *dev_data, const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag &type_tag);
-}  // namespace core_validation
 
 #endif  // CORE_VALIDATION_TYPES_H_
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index 7d8b2d8..9cb7df2 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,9 @@
 // Allow use of STL min and max functions in Windows
 #define NOMINMAX
 
+#include "chassis.h"
+#include "core_validation_error_enums.h"
+#include "core_validation.h"
 #include "descriptor_sets.h"
 #include "hash_vk_types.h"
 #include "vk_enum_string_helper.h"
@@ -30,6 +33,7 @@
 #include "buffer_validation.h"
 #include <sstream>
 #include <algorithm>
+#include <array>
 #include <memory>
 
 // ExtendedBinding collects a VkDescriptorSetLayoutBinding and any extended
@@ -136,6 +140,7 @@
     hash_util::HashCombiner hc;
     hc << flags_;
     hc.Combine(bindings_);
+    hc.Combine(binding_flags_);
     return hc.Value();
 }
 //
@@ -335,8 +340,13 @@
         // Verify next consecutive binding matches type, stage flags & immutable sampler use
         if (!IsNextBindingConsistent(current_binding++)) {
             std::stringstream error_str;
-            error_str << "Attempting " << type << " descriptor set " << set << " binding #" << orig_binding << " with #"
-                      << update_count
+            error_str << "Attempting " << type;
+            if (IsPushDescriptor()) {
+                error_str << " push descriptors";
+            } else {
+                error_str << " descriptor set " << set;
+            }
+            error_str << " binding #" << orig_binding << " with #" << update_count
                       << " descriptors being updated but this update oversteps the bounds of this binding and the next binding is "
                          "not consistent with current binding so this update is invalid.";
             *error_msg = error_str.str();
@@ -587,9 +597,9 @@
       pool_state_(nullptr),
       p_layout_(layout),
       device_data_(dev_data),
-      limits_(GetPhysDevProperties(dev_data)->properties.limits),
+      limits_(dev_data->phys_dev_props.limits),
       variable_count_(variable_count) {
-    pool_state_ = GetDescriptorPoolState(dev_data, pool);
+    pool_state_ = dev_data->GetDescriptorPoolState(pool);
     // Foreach binding, create default descriptors of given type
     descriptors_.reserve(p_layout_->GetTotalDescriptorCount());
     for (uint32_t i = 0; i < p_layout_->GetBindingCount(); ++i) {
@@ -640,7 +650,7 @@
                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
                     descriptors_.emplace_back(new InlineUniformDescriptor(type));
                 break;
-            case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX:
+            case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
                     descriptors_.emplace_back(new AccelerationStructureDescriptor(type));
                 break;
@@ -713,7 +723,8 @@
         }
 
         for (uint32_t i = index_range.start; i < index_range.end; ++i, ++array_idx) {
-            if ((p_layout_->GetDescriptorBindingFlagsFromBinding(binding) & VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT) ||
+            if ((p_layout_->GetDescriptorBindingFlagsFromBinding(binding) &
+                 (VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT)) ||
                 descriptors_[i]->GetClass() == InlineUniform) {
                 // Can't validate the descriptor because it may not have been updated,
                 // or the view could have been destroyed
@@ -729,7 +740,7 @@
                 if (descriptor_class == GeneralBuffer) {
                     // Verify that buffers are valid
                     auto buffer = static_cast<BufferDescriptor *>(descriptors_[i].get())->GetBuffer();
-                    auto buffer_node = GetBufferState(device_data_, buffer);
+                    auto buffer_node = device_data_->GetBufferState(buffer);
                     if (!buffer_node) {
                         std::stringstream error_str;
                         error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
@@ -738,7 +749,7 @@
                         return false;
                     } else if (!buffer_node->sparse) {
                         for (auto mem_binding : buffer_node->GetBoundMemory()) {
-                            if (!GetMemObjInfo(device_data_, mem_binding)) {
+                            if (!device_data_->GetMemObjInfo(mem_binding)) {
                                 std::stringstream error_str;
                                 error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
                                           << " uses buffer " << buffer << " that references invalid memory " << mem_binding << ".";
@@ -787,7 +798,7 @@
                     }
                     auto reqs = binding_pair.second;
 
-                    auto image_view_state = GetImageViewState(device_data_, image_view);
+                    auto image_view_state = device_data_->GetImageViewState(image_view);
                     if (nullptr == image_view_state) {
                         // Image view must have been destroyed since initial update. Could potentially flag the descriptor
                         //  as "invalid" (updated = false) at DestroyImageView() time and detect this error at bind time
@@ -820,7 +831,7 @@
                         return false;
                     }
 
-                    auto image_node = GetImageState(device_data_, image_view_ci.image);
+                    auto image_node = device_data_->GetImageState(image_view_ci.image);
                     assert(image_node);
                     // Verify Image Layout
                     // Copy first mip level into sub_layers and loop over each mip level to verify layout
@@ -833,12 +844,14 @@
                          cur_level < image_view_ci.subresourceRange.levelCount; ++cur_level) {
                         sub_layers.mipLevel = cur_level;
                         // No "invalid layout" VUID required for this call, since the optimal_layout parameter is UNDEFINED.
-                        VerifyImageLayout(device_data_, cb_node, image_node, sub_layers, image_layout, VK_IMAGE_LAYOUT_UNDEFINED,
-                                          caller, kVUIDUndefined, "VUID-VkDescriptorImageInfo-imageLayout-00344", &hit_error);
+                        device_data_->VerifyImageLayout(device_data_, cb_node, image_node, sub_layers, image_layout,
+                                                        VK_IMAGE_LAYOUT_UNDEFINED, caller, kVUIDUndefined,
+                                                        "VUID-VkDescriptorImageInfo-imageLayout-00344", &hit_error);
                         if (hit_error) {
                             *error =
-                                "Image layout specified at vkUpdateDescriptorSets() time doesn't match actual image layout at time "
-                                "descriptor is used. See previous error callback for specific details.";
+                                "Image layout specified at vkUpdateDescriptorSet* or vkCmdPushDescriptorSet* time "
+                                "doesn't match actual image layout at time descriptor is used. See previous error callback for "
+                                "specific details.";
                             return false;
                         }
                     }
@@ -858,6 +871,22 @@
                         *error = error_str.str();
                         return false;
                     }
+                } else if (descriptor_class == TexelBuffer) {
+                    auto texel_buffer = static_cast<TexelDescriptor *>(descriptors_[i].get());
+                    auto buffer_view = device_data_->GetBufferViewState(texel_buffer->GetBufferView());
+
+                    auto reqs = binding_pair.second;
+                    auto format_bits = DescriptorRequirementsBitsFromFormat(buffer_view->create_info.format);
+
+                    if (!(reqs & format_bits)) {
+                        // bad component type
+                        std::stringstream error_str;
+                        error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i << " requires "
+                                  << StringDescriptorReqComponentType(reqs) << " component type, but bound descriptor format is "
+                                  << string_VkFormat(buffer_view->create_info.format) << ".";
+                        *error = error_str.str();
+                        return false;
+                    }
                 }
                 if (descriptor_class == ImageSampler || descriptor_class == PlainSampler) {
                     // Verify Sampler still valid
@@ -905,7 +934,7 @@
                 for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
                     if (descriptors_[start_idx + i]->updated) {
                         auto bufferview = static_cast<TexelDescriptor *>(descriptors_[start_idx + i].get())->GetBufferView();
-                        auto bv_state = GetBufferViewState(device_data_, bufferview);
+                        auto bv_state = device_data_->GetBufferViewState(bufferview);
                         if (bv_state) {
                             buffer_set->insert(bv_state->create_info.buffer);
                             num_updates++;
@@ -926,8 +955,17 @@
 }
 // Set is being deleted or updates so invalidate all bound cmd buffers
 void cvdescriptorset::DescriptorSet::InvalidateBoundCmdBuffers() {
-    core_validation::InvalidateCommandBuffers(device_data_, cb_bindings, {HandleToUint64(set_), kVulkanObjectTypeDescriptorSet});
+    device_data_->InvalidateCommandBuffers(device_data_, cb_bindings, {HandleToUint64(set_), kVulkanObjectTypeDescriptorSet});
 }
+
+// Loop through the write updates to do for a push descriptor set, ignoring dstSet
+void cvdescriptorset::DescriptorSet::PerformPushDescriptorsUpdate(uint32_t write_count, const VkWriteDescriptorSet *p_wds) {
+    assert(IsPushDescriptor());
+    for (uint32_t i = 0; i < write_count; i++) {
+        PerformWriteUpdate(&p_wds[i]);
+    }
+}
+
 // Perform write update in given update struct
 void cvdescriptorset::DescriptorSet::PerformWriteUpdate(const VkWriteDescriptorSet *update) {
     // Perform update on a per-binding basis as consecutive updates roll over to next binding
@@ -956,26 +994,28 @@
 }
 // Validate Copy update
 bool cvdescriptorset::DescriptorSet::ValidateCopyUpdate(const debug_report_data *report_data, const VkCopyDescriptorSet *update,
-                                                        const DescriptorSet *src_set, std::string *error_code,
-                                                        std::string *error_msg) {
+                                                        const DescriptorSet *src_set, const char *func_name,
+                                                        std::string *error_code, std::string *error_msg) {
     // Verify dst layout still valid
     if (p_layout_->IsDestroyed()) {
         *error_code = "VUID-VkCopyDescriptorSet-dstSet-parameter";
         string_sprintf(error_msg,
-                       "Cannot call vkUpdateDescriptorSets() to perform copy update on descriptor set dstSet 0x%" PRIxLEAST64
-                       " created with destroyed VkDescriptorSetLayout 0x%" PRIxLEAST64,
-                       HandleToUint64(set_), HandleToUint64(p_layout_->GetDescriptorSetLayout()));
+                       "Cannot call %s to perform copy update on descriptor set dstSet %s"
+                       " created with destroyed VkDescriptorSetLayout %s.",
+                       func_name, report_data->FormatHandle(set_).c_str(),
+                       report_data->FormatHandle(p_layout_->GetDescriptorSetLayout()).c_str());
         return false;
     }
 
     // Verify src layout still valid
     if (src_set->p_layout_->IsDestroyed()) {
         *error_code = "VUID-VkCopyDescriptorSet-srcSet-parameter";
-        string_sprintf(
-            error_msg,
-            "Cannot call vkUpdateDescriptorSets() to perform copy update of dstSet 0x%" PRIxLEAST64
-            " from descriptor set srcSet 0x%" PRIxLEAST64 " created with destroyed VkDescriptorSetLayout 0x%" PRIxLEAST64,
-            HandleToUint64(set_), HandleToUint64(src_set->set_), HandleToUint64(src_set->p_layout_->GetDescriptorSetLayout()));
+        string_sprintf(error_msg,
+                       "Cannot call %s to perform copy update of dstSet %s"
+                       " from descriptor set srcSet %s"
+                       " created with destroyed VkDescriptorSetLayout %s.",
+                       func_name, report_data->FormatHandle(set_).c_str(), report_data->FormatHandle(src_set->set_).c_str(),
+                       report_data->FormatHandle(src_set->p_layout_->GetDescriptorSetLayout()).c_str());
         return false;
     }
 
@@ -1000,7 +1040,7 @@
         // TODO : Re-using Free Idle error code, need copy update idle error code
         *error_code = "VUID-vkFreeDescriptorSets-pDescriptorSets-00309";
         std::stringstream error_str;
-        error_str << "Cannot call vkUpdateDescriptorSets() to perform copy update on descriptor set " << set_
+        error_str << "Cannot call " << func_name << " to perform copy update on descriptor set " << set_
                   << " that is in use by a command buffer";
         *error_msg = error_str.str();
         return false;
@@ -1141,7 +1181,7 @@
     }
 
     // Update parameters all look good and descriptor updated so verify update contents
-    if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, error_code, error_msg)) return false;
+    if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, func_name, error_code, error_msg)) return false;
 
     // All checks passed so update is good
     return true;
@@ -1187,6 +1227,11 @@
     // resources
     for (auto binding_req_pair : binding_req_map) {
         auto binding = binding_req_pair.first;
+        // We aren't validating descriptors created with PARTIALLY_BOUND or UPDATE_AFTER_BIND, so don't record state
+        if (p_layout_->GetDescriptorBindingFlagsFromBinding(binding) &
+            (VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT)) {
+            continue;
+        }
         auto range = p_layout_->GetGlobalIndexRangeFromBinding(binding);
         for (uint32_t i = range.start; i < range.end; ++i) {
             descriptors_[i]->UpdateDrawState(device_data_, cb_node);
@@ -1272,15 +1317,15 @@
     }
 }
 // Validate given sampler. Currently this only checks to make sure it exists in the samplerMap
-bool cvdescriptorset::ValidateSampler(const VkSampler sampler, const layer_data *dev_data) {
-    return (GetSamplerState(dev_data, sampler) != nullptr);
+bool cvdescriptorset::ValidateSampler(const VkSampler sampler, layer_data *dev_data) {
+    return (dev_data->GetSamplerState(sampler) != nullptr);
 }
 
 bool cvdescriptorset::ValidateImageUpdate(VkImageView image_view, VkImageLayout image_layout, VkDescriptorType type,
-                                          const layer_data *dev_data, std::string *error_code, std::string *error_msg) {
-    // TODO : Defaulting to 00943 for all cases here. Need to create new error codes for various cases.
+                                          layer_data *dev_data, const char *func_name, std::string *error_code,
+                                          std::string *error_msg) {
     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00326";
-    auto iv_state = GetImageViewState(dev_data, image_view);
+    auto iv_state = dev_data->GetImageViewState(image_view);
     if (!iv_state) {
         std::stringstream error_str;
         error_str << "Invalid VkImageView: " << image_view;
@@ -1294,15 +1339,14 @@
     VkImage image = iv_state->create_info.image;
     VkFormat format = VK_FORMAT_MAX_ENUM;
     VkImageUsageFlags usage = 0;
-    auto image_node = GetImageState(dev_data, image);
+    auto image_node = dev_data->GetImageState(image);
     if (image_node) {
         format = image_node->createInfo.format;
         usage = image_node->createInfo.usage;
         // Validate that memory is bound to image
         // TODO: This should have its own valid usage id apart from 2524 which is from CreateImageView case. The only
         //  the error here occurs is if memory bound to a created imageView has been freed.
-        if (ValidateMemoryIsBoundToImage(dev_data, image_node, "vkUpdateDescriptorSets()",
-                                         "VUID-VkImageViewCreateInfo-image-01020")) {
+        if (dev_data->ValidateMemoryIsBoundToImage(dev_data, image_node, func_name, "VUID-VkImageViewCreateInfo-image-01020")) {
             *error_code = "VUID-VkImageViewCreateInfo-image-01020";
             *error_msg = "No memory bound to image.";
             return false;
@@ -1403,7 +1447,7 @@
     // under vkCreateImage()
     // TODO : Need to also validate case "VUID-VkWriteDescriptorSet-descriptorType-00336" where STORAGE_IMAGE & INPUT_ATTACH types
     // must have been created with identify swizzle
-    std::string error_usage_bit;
+    const char *error_usage_bit = nullptr;
     switch (type) {
         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
@@ -1451,7 +1495,7 @@
         default:
             break;
     }
-    if (!error_usage_bit.empty()) {
+    if (error_usage_bit) {
         std::stringstream error_str;
         error_str << "ImageView (" << image_view << ") with usage mask 0x" << usage
                   << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
@@ -1459,6 +1503,46 @@
         *error_msg = error_str.str();
         return false;
     }
+
+    if ((type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) || (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
+        // Test that the layout is compatible with the descriptorType for the two sampled image types
+        const static std::array<VkImageLayout, 3> valid_layouts = {
+            {VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL}};
+
+        struct ExtensionLayout {
+            VkImageLayout layout;
+            bool DeviceExtensions::*extension;
+        };
+
+        const static std::array<ExtensionLayout, 3> extended_layouts{
+            {//  Note double brace req'd for aggregate initialization
+             {VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, &DeviceExtensions::vk_khr_shared_presentable_image},
+             {VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2},
+             {VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2}}};
+        auto is_layout = [image_layout, dev_data](const ExtensionLayout &ext_layout) {
+            return dev_data->device_extensions.*(ext_layout.extension) && (ext_layout.layout == image_layout);
+        };
+
+        bool valid_layout = (std::find(valid_layouts.cbegin(), valid_layouts.cend(), image_layout) != valid_layouts.cend()) ||
+                            std::any_of(extended_layouts.cbegin(), extended_layouts.cend(), is_layout);
+
+        if (!valid_layout) {
+            *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01403";
+            std::stringstream error_str;
+            error_str << "Descriptor update with descriptorType " << string_VkDescriptorType(type)
+                      << " is being updated with invalid imageLayout " << string_VkImageLayout(image_layout)
+                      << ". Allowed layouts are: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
+                      << "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL";
+            for (auto &ext_layout : extended_layouts) {
+                if (dev_data->device_extensions.*(ext_layout.extension)) {
+                    error_str << ", " << string_VkImageLayout(ext_layout.layout);
+                }
+            }
+            *error_msg = error_str.str();
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -1479,8 +1563,8 @@
 
 void cvdescriptorset::SamplerDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     if (!immutable_) {
-        auto sampler_state = GetSamplerState(dev_data, sampler_);
-        if (sampler_state) core_validation::AddCommandBufferBindingSampler(cb_node, sampler_state);
+        auto sampler_state = dev_data->GetSamplerState(sampler_);
+        if (sampler_state) dev_data->AddCommandBufferBindingSampler(cb_node, sampler_state);
     }
 }
 
@@ -1519,15 +1603,17 @@
 void cvdescriptorset::ImageSamplerDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     // First add binding for any non-immutable sampler
     if (!immutable_) {
-        auto sampler_state = GetSamplerState(dev_data, sampler_);
-        if (sampler_state) core_validation::AddCommandBufferBindingSampler(cb_node, sampler_state);
+        auto sampler_state = dev_data->GetSamplerState(sampler_);
+        if (sampler_state) dev_data->AddCommandBufferBindingSampler(cb_node, sampler_state);
     }
     // Add binding for image
-    auto iv_state = GetImageViewState(dev_data, image_view_);
+    auto iv_state = dev_data->GetImageViewState(image_view_);
     if (iv_state) {
-        core_validation::AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
+        dev_data->AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
     }
-    SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
+    if (image_view_) {
+        dev_data->SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
+    }
 }
 
 cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type)
@@ -1554,11 +1640,13 @@
 
 void cvdescriptorset::ImageDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
     // Add binding for image
-    auto iv_state = GetImageViewState(dev_data, image_view_);
+    auto iv_state = dev_data->GetImageViewState(image_view_);
     if (iv_state) {
-        core_validation::AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
+        dev_data->AddCommandBufferBindingImageView(dev_data, cb_node, iv_state);
     }
-    SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
+    if (image_view_) {
+        dev_data->SetImageViewLayout(dev_data, cb_node, image_view_, image_layout_);
+    }
 }
 
 cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type)
@@ -1591,8 +1679,8 @@
 }
 
 void cvdescriptorset::BufferDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
-    auto buffer_node = GetBufferState(dev_data, buffer_);
-    if (buffer_node) core_validation::AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_node);
+    auto buffer_node = dev_data->GetBufferState(buffer_);
+    if (buffer_node) dev_data->AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_node);
 }
 
 cvdescriptorset::TexelDescriptor::TexelDescriptor(const VkDescriptorType type) : buffer_view_(VK_NULL_HANDLE), storage_(false) {
@@ -1612,9 +1700,9 @@
 }
 
 void cvdescriptorset::TexelDescriptor::UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
-    auto bv_state = GetBufferViewState(dev_data, buffer_view_);
+    auto bv_state = dev_data->GetBufferViewState(buffer_view_);
     if (bv_state) {
-        core_validation::AddCommandBufferBindingBufferView(dev_data, cb_node, bv_state);
+        dev_data->AddCommandBufferBindingBufferView(dev_data, cb_node, bv_state);
     }
 }
 
@@ -1623,29 +1711,27 @@
 // If the update hits an issue for which the callback returns "true", meaning that the call down the chain should
 //  be skipped, then true is returned.
 // If there is no issue with the update, then false is returned.
-bool cvdescriptorset::ValidateUpdateDescriptorSets(const debug_report_data *report_data, const layer_data *dev_data,
-                                                   uint32_t write_count, const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
-                                                   const VkCopyDescriptorSet *p_cds) {
+bool CoreChecks::ValidateUpdateDescriptorSets(const debug_report_data *report_data, const layer_data *dev_data,
+                                              uint32_t write_count, const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
+                                              const VkCopyDescriptorSet *p_cds, const char *func_name) {
     bool skip = false;
     // Validate Write updates
     for (uint32_t i = 0; i < write_count; i++) {
         auto dest_set = p_wds[i].dstSet;
-        auto set_node = core_validation::GetSetNode(dev_data, dest_set);
+        auto set_node = GetSetNode(dest_set);
         if (!set_node) {
-            skip |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                        HandleToUint64(dest_set), kVUID_Core_DrawState_InvalidDescriptorSet,
-                        "Cannot call vkUpdateDescriptorSets() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.",
-                        HandleToUint64(dest_set));
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                            HandleToUint64(dest_set), kVUID_Core_DrawState_InvalidDescriptorSet,
+                            "Cannot call %s on descriptor set %s that has not been allocated.", func_name,
+                            report_data->FormatHandle(dest_set).c_str());
         } else {
             std::string error_code;
             std::string error_str;
-            if (!set_node->ValidateWriteUpdate(report_data, &p_wds[i], &error_code, &error_str)) {
+            if (!set_node->ValidateWriteUpdate(report_data, &p_wds[i], func_name, &error_code, &error_str)) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                                 HandleToUint64(dest_set), error_code,
-                                "vkUpdateDescriptorSets() failed write update validation for Descriptor Set 0x%" PRIx64
-                                " with error: %s.",
-                                HandleToUint64(dest_set), error_str.c_str());
+                                "%s failed write update validation for Descriptor Set %s with error: %s.", func_name,
+                                report_data->FormatHandle(dest_set).c_str(), error_str.c_str());
             }
         }
     }
@@ -1653,19 +1739,18 @@
     for (uint32_t i = 0; i < copy_count; ++i) {
         auto dst_set = p_cds[i].dstSet;
         auto src_set = p_cds[i].srcSet;
-        auto src_node = core_validation::GetSetNode(dev_data, src_set);
-        auto dst_node = core_validation::GetSetNode(dev_data, dst_set);
+        auto src_node = GetSetNode(src_set);
+        auto dst_node = GetSetNode(dst_set);
         // Object_tracker verifies that src & dest descriptor set are valid
         assert(src_node);
         assert(dst_node);
         std::string error_code;
         std::string error_str;
-        if (!dst_node->ValidateCopyUpdate(report_data, &p_cds[i], src_node, &error_code, &error_str)) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                            HandleToUint64(dst_set), error_code,
-                            "vkUpdateDescriptorSets() failed copy update from Descriptor Set 0x%" PRIx64
-                            " to Descriptor Set 0x%" PRIx64 " with error: %s.",
-                            HandleToUint64(src_set), HandleToUint64(dst_set), error_str.c_str());
+        if (!dst_node->ValidateCopyUpdate(report_data, &p_cds[i], src_node, func_name, &error_code, &error_str)) {
+            skip |= log_msg(
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(dst_set),
+                error_code, "%s failed copy update from Descriptor Set %s to Descriptor Set %s with error: %s.", func_name,
+                report_data->FormatHandle(src_set).c_str(), report_data->FormatHandle(dst_set).c_str(), error_str.c_str());
         }
     }
     return skip;
@@ -1676,14 +1761,13 @@
 //  with the same set of updates.
 // This is split from the validate code to allow validation prior to calling down the chain, and then update after
 //  calling down the chain.
-void cvdescriptorset::PerformUpdateDescriptorSets(const layer_data *dev_data, uint32_t write_count,
-                                                  const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
-                                                  const VkCopyDescriptorSet *p_cds) {
+void cvdescriptorset::PerformUpdateDescriptorSets(layer_data *dev_data, uint32_t write_count, const VkWriteDescriptorSet *p_wds,
+                                                  uint32_t copy_count, const VkCopyDescriptorSet *p_cds) {
     // Write updates first
     uint32_t i = 0;
     for (i = 0; i < write_count; ++i) {
         auto dest_set = p_wds[i].dstSet;
-        auto set_node = core_validation::GetSetNode(dev_data, dest_set);
+        auto set_node = dev_data->GetSetNode(dest_set);
         if (set_node) {
             set_node->PerformWriteUpdate(&p_wds[i]);
         }
@@ -1692,24 +1776,24 @@
     for (i = 0; i < copy_count; ++i) {
         auto dst_set = p_cds[i].dstSet;
         auto src_set = p_cds[i].srcSet;
-        auto src_node = core_validation::GetSetNode(dev_data, src_set);
-        auto dst_node = core_validation::GetSetNode(dev_data, dst_set);
+        auto src_node = dev_data->GetSetNode(src_set);
+        auto dst_node = dev_data->GetSetNode(dst_set);
         if (src_node && dst_node) {
             dst_node->PerformCopyUpdate(&p_cds[i], src_node);
         }
     }
 }
-// This helper function carries out the state updates for descriptor updates peformed via update templates. It basically collects
-// data and leverages the PerformUpdateDescriptor helper functions to do this.
-void cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
-                                                                 std::unique_ptr<TEMPLATE_STATE> const &template_state,
-                                                                 const void *pData) {
-    auto const &create_info = template_state->create_info;
 
-    // Create a vector of write structs
-    std::vector<VkWriteDescriptorSet> desc_writes;
-    std::vector<VkWriteDescriptorSetInlineUniformBlockEXT> inline_infos(create_info.descriptorUpdateEntryCount);
-    auto layout_obj = GetDescriptorSetLayout(device_data, create_info.descriptorSetLayout);
+cvdescriptorset::DecodedTemplateUpdate::DecodedTemplateUpdate(layer_data *device_data, VkDescriptorSet descriptorSet,
+                                                              const TEMPLATE_STATE *template_state, const void *pData,
+                                                              VkDescriptorSetLayout push_layout) {
+    auto const &create_info = template_state->create_info;
+    inline_infos.resize(create_info.descriptorUpdateEntryCount);  // Make sure we have one if we need it
+    desc_writes.reserve(create_info.descriptorUpdateEntryCount);  // emplaced, so reserved without initialization
+    VkDescriptorSetLayout effective_dsl = create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
+                                              ? create_info.descriptorSetLayout
+                                              : push_layout;
+    auto layout_obj = GetDescriptorSetLayout(device_data, effective_dsl);
 
     // Create a WriteDescriptorSet struct for each template update entry
     for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) {
@@ -1776,26 +1860,70 @@
             dst_array_element++;
         }
     }
-    PerformUpdateDescriptorSets(device_data, static_cast<uint32_t>(desc_writes.size()), desc_writes.data(), 0, NULL);
 }
+// These helper functions carry out the validate and record descriptor updates peformed via update templates. They decode
+// the templatized data and leverage the non-template UpdateDescriptor helper functions.
+bool CoreChecks::ValidateUpdateDescriptorSetsWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
+                                                             const TEMPLATE_STATE *template_state, const void *pData) {
+    // Translate the templated update into a normal update for validation...
+    cvdescriptorset::DecodedTemplateUpdate decoded_update(device_data, descriptorSet, template_state, pData);
+    return ValidateUpdateDescriptorSets(GetReportData(), device_data, static_cast<uint32_t>(decoded_update.desc_writes.size()),
+                                        decoded_update.desc_writes.data(), 0, NULL, "vkUpdateDescriptorSetWithTemplate()");
+}
+
+void CoreChecks::PerformUpdateDescriptorSetsWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
+                                                            const TEMPLATE_STATE *template_state, const void *pData) {
+    // Translate the templated update into a normal update for validation...
+    cvdescriptorset::DecodedTemplateUpdate decoded_update(device_data, descriptorSet, template_state, pData);
+    cvdescriptorset::PerformUpdateDescriptorSets(device_data, static_cast<uint32_t>(decoded_update.desc_writes.size()),
+                                                 decoded_update.desc_writes.data(), 0, NULL);
+}
+
+std::string cvdescriptorset::DescriptorSet::StringifySetAndLayout() const {
+    std::string out;
+    uint64_t layout_handle = HandleToUint64(p_layout_->GetDescriptorSetLayout());
+    if (IsPushDescriptor()) {
+        string_sprintf(&out, "Push Descriptors defined with VkDescriptorSetLayout 0x%" PRIxLEAST64, layout_handle);
+    } else {
+        string_sprintf(&out, "VkDescriptorSet 0x%" PRIxLEAST64 "allocated with VkDescriptorSetLayout 0x%" PRIxLEAST64,
+                       HandleToUint64(set_), layout_handle);
+    }
+    return out;
+};
+
+// Loop through the write updates to validate for a push descriptor set, ignoring dstSet
+bool cvdescriptorset::DescriptorSet::ValidatePushDescriptorsUpdate(const debug_report_data *report_data, uint32_t write_count,
+                                                                   const VkWriteDescriptorSet *p_wds, const char *func_name) {
+    assert(IsPushDescriptor());
+    bool skip = false;
+    for (uint32_t i = 0; i < write_count; i++) {
+        std::string error_code;
+        std::string error_str;
+        if (!ValidateWriteUpdate(report_data, &p_wds[i], func_name, &error_code, &error_str)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
+                            HandleToUint64(p_layout_->GetDescriptorSetLayout()), error_code, "%s failed update validation: %s.",
+                            func_name, error_str.c_str());
+        }
+    }
+    return skip;
+}
+
 // Validate the state for a given write update but don't actually perform the update
 //  If an error would occur for this update, return false and fill in details in error_msg string
 bool cvdescriptorset::DescriptorSet::ValidateWriteUpdate(const debug_report_data *report_data, const VkWriteDescriptorSet *update,
-                                                         std::string *error_code, std::string *error_msg) {
+                                                         const char *func_name, std::string *error_code, std::string *error_msg) {
     // Verify dst layout still valid
     if (p_layout_->IsDestroyed()) {
         *error_code = "VUID-VkWriteDescriptorSet-dstSet-00320";
-        string_sprintf(error_msg,
-                       "Cannot call vkUpdateDescriptorSets() to perform write update on descriptor set 0x%" PRIxLEAST64
-                       " created with destroyed VkDescriptorSetLayout 0x%" PRIxLEAST64,
-                       HandleToUint64(set_), HandleToUint64(p_layout_->GetDescriptorSetLayout()));
+        string_sprintf(error_msg, "Cannot call %s to perform write update on %s which has been destroyed", func_name,
+                       StringifySetAndLayout().c_str());
         return false;
     }
     // Verify dst binding exists
     if (!p_layout_->HasBinding(update->dstBinding)) {
         *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00315";
         std::stringstream error_str;
-        error_str << "DescriptorSet " << set_ << " does not have binding " << update->dstBinding;
+        error_str << StringifySetAndLayout() << " does not have binding " << update->dstBinding;
         *error_msg = error_str.str();
         return false;
     } else {
@@ -1803,7 +1931,7 @@
         if (0 == p_layout_->GetDescriptorCountFromBinding(update->dstBinding)) {
             *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00316";
             std::stringstream error_str;
-            error_str << "DescriptorSet " << set_ << " cannot updated binding " << update->dstBinding << " that has 0 descriptors";
+            error_str << StringifySetAndLayout() << " cannot updated binding " << update->dstBinding << " that has 0 descriptors";
             *error_msg = error_str.str();
             return false;
         }
@@ -1815,7 +1943,7 @@
         // TODO : Re-using Free Idle error code, need write update idle error code
         *error_code = "VUID-vkFreeDescriptorSets-pDescriptorSets-00309";
         std::stringstream error_str;
-        error_str << "Cannot call vkUpdateDescriptorSets() to perform write update on descriptor set " << set_
+        error_str << "Cannot call " << func_name << " to perform write update on " << StringifySetAndLayout()
                   << " that is in use by a command buffer";
         *error_msg = error_str.str();
         return false;
@@ -1826,7 +1954,7 @@
     if (type != update->descriptorType) {
         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00319";
         std::stringstream error_str;
-        error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with type "
+        error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding << " with type "
                   << string_VkDescriptorType(type) << " but update type is " << string_VkDescriptorType(update->descriptorType);
         *error_msg = error_str.str();
         return false;
@@ -1834,7 +1962,7 @@
     if (update->descriptorCount > (descriptors_.size() - start_idx)) {
         *error_code = "VUID-VkWriteDescriptorSet-dstArrayElement-00321";
         std::stringstream error_str;
-        error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+        error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding << " with "
                   << descriptors_.size() - start_idx
                   << " descriptors in that binding and all successive bindings of the set, but update of "
                   << update->descriptorCount << " descriptors combined with update array element offset of "
@@ -1846,7 +1974,7 @@
         if ((update->dstArrayElement % 4) != 0) {
             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02219";
             std::stringstream error_str;
-            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+            error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding << " with "
                       << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
             *error_msg = error_str.str();
             return false;
@@ -1854,7 +1982,7 @@
         if ((update->descriptorCount % 4) != 0) {
             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02220";
             std::stringstream error_str;
-            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+            error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding << " with "
                       << "descriptorCount  " << update->descriptorCount << " not a multiple of 4";
             *error_msg = error_str.str();
             return false;
@@ -1864,10 +1992,12 @@
             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02221";
             std::stringstream error_str;
             if (!write_inline_info) {
-                error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding
+                          << " with "
                           << "VkWriteDescriptorSetInlineUniformBlockEXT missing";
             } else {
-                error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding
+                          << " with "
                           << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize
                           << " not equal to "
                           << "VkWriteDescriptorSet descriptorCount " << update->descriptorCount;
@@ -1879,7 +2009,7 @@
         if (write_inline_info && (write_inline_info->dataSize % 4) != 0) {
             *error_code = "VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-02222";
             std::stringstream error_str;
-            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+            error_str << "Attempting write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding << " with "
                       << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize
                       << " not a multiple of 4";
             *error_msg = error_str.str();
@@ -1894,9 +2024,9 @@
         return false;
     }
     // Update is within bounds and consistent so last step is to validate update contents
-    if (!VerifyWriteUpdateContents(update, start_idx, error_code, error_msg)) {
+    if (!VerifyWriteUpdateContents(update, start_idx, func_name, error_code, error_msg)) {
         std::stringstream error_str;
-        error_str << "Write update to descriptor in set " << set_ << " binding #" << update->dstBinding
+        error_str << "Write update to " << StringifySetAndLayout() << " binding #" << update->dstBinding
                   << " failed with error message: " << error_msg->c_str();
         *error_msg = error_str.str();
         return false;
@@ -1910,7 +2040,7 @@
                                                          std::string *error_code, std::string *error_msg) const {
     // Verify that usage bits set correctly for given type
     auto usage = buffer_node->createInfo.usage;
-    std::string error_usage_bit;
+    const char *error_usage_bit = nullptr;
     switch (type) {
         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
             if (!(usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) {
@@ -1941,7 +2071,7 @@
         default:
             break;
     }
-    if (!error_usage_bit.empty()) {
+    if (error_usage_bit) {
         std::stringstream error_str;
         error_str << "Buffer (" << buffer_node->buffer << ") with usage mask 0x" << usage
                   << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
@@ -1959,13 +2089,14 @@
 //  5. range and offset are within the device's limits
 // If there's an error, update the error_msg string with details and return false, else return true
 bool cvdescriptorset::DescriptorSet::ValidateBufferUpdate(VkDescriptorBufferInfo const *buffer_info, VkDescriptorType type,
-                                                          std::string *error_code, std::string *error_msg) const {
+                                                          const char *func_name, std::string *error_code,
+                                                          std::string *error_msg) const {
     // First make sure that buffer is valid
-    auto buffer_node = GetBufferState(device_data_, buffer_info->buffer);
+    auto buffer_node = device_data_->GetBufferState(buffer_info->buffer);
     // Any invalid buffer should already be caught by object_tracker
     assert(buffer_node);
-    if (ValidateMemoryIsBoundToBuffer(device_data_, buffer_node, "vkUpdateDescriptorSets()",
-                                      "VUID-VkWriteDescriptorSet-descriptorType-00329")) {
+    if (device_data_->ValidateMemoryIsBoundToBuffer(device_data_, buffer_node, func_name,
+                                                    "VUID-VkWriteDescriptorSet-descriptorType-00329")) {
         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00329";
         *error_msg = "No memory bound to buffer.";
         return false;
@@ -2046,20 +2177,40 @@
 
 // Verify that the contents of the update are ok, but don't perform actual update
 bool cvdescriptorset::DescriptorSet::VerifyWriteUpdateContents(const VkWriteDescriptorSet *update, const uint32_t index,
-                                                               std::string *error_code, std::string *error_msg) const {
+                                                               const char *func_name, std::string *error_code,
+                                                               std::string *error_msg) const {
     switch (update->descriptorType) {
         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
                 // Validate image
                 auto image_view = update->pImageInfo[di].imageView;
                 auto image_layout = update->pImageInfo[di].imageLayout;
-                if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error_code, error_msg)) {
+                if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, func_name, error_code,
+                                         error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted write update to combined image sampler descriptor failed due to: "
                               << error_msg->c_str();
                     *error_msg = error_str.str();
                     return false;
                 }
+                if (device_data_->GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
+                    ImageSamplerDescriptor *desc = (ImageSamplerDescriptor *)descriptors_[index].get();
+                    if (desc->IsImmutableSampler()) {
+                        auto sampler_state = device_data_->GetSamplerState(desc->GetSampler());
+                        auto iv_state = device_data_->GetImageViewState(image_view);
+                        if (iv_state && sampler_state) {
+                            if (iv_state->samplerConversion != sampler_state->samplerConversion) {
+                                *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01948";
+                                std::stringstream error_str;
+                                error_str << "Attempted write update to combined image sampler and image view and sampler ycbcr "
+                                             "conversions are not identical, sampler: "
+                                          << desc->GetSampler() << " image view: " << iv_state->image_view << ".";
+                                *error_msg = error_str.str();
+                                return false;
+                            }
+                        }
+                    }
+                }
             }
         }
         // fall through
@@ -2086,7 +2237,8 @@
             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
                 auto image_view = update->pImageInfo[di].imageView;
                 auto image_layout = update->pImageInfo[di].imageLayout;
-                if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error_code, error_msg)) {
+                if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, func_name, error_code,
+                                         error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted write update to image descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2099,7 +2251,7 @@
         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
                 auto buffer_view = update->pTexelBufferView[di];
-                auto bv_state = GetBufferViewState(device_data_, buffer_view);
+                auto bv_state = device_data_->GetBufferViewState(buffer_view);
                 if (!bv_state) {
                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
                     std::stringstream error_str;
@@ -2108,7 +2260,7 @@
                     return false;
                 }
                 auto buffer = bv_state->create_info.buffer;
-                auto buffer_state = GetBufferState(device_data_, buffer);
+                auto buffer_state = device_data_->GetBufferState(buffer);
                 // Verify that buffer underlying the view hasn't been destroyed prematurely
                 if (!buffer_state) {
                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
@@ -2131,7 +2283,7 @@
         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
-                if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, error_code, error_msg)) {
+                if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, func_name, error_code, error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted write update to buffer descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2142,7 +2294,7 @@
         }
         case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
             break;
-        case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX:
+        case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
             // XXX TODO
             break;
         default:
@@ -2154,8 +2306,8 @@
 }
 // Verify that the contents of the update are ok, but don't perform actual update
 bool cvdescriptorset::DescriptorSet::VerifyCopyUpdateContents(const VkCopyDescriptorSet *update, const DescriptorSet *src_set,
-                                                              VkDescriptorType type, uint32_t index, std::string *error_code,
-                                                              std::string *error_msg) const {
+                                                              VkDescriptorType type, uint32_t index, const char *func_name,
+                                                              std::string *error_code, std::string *error_msg) const {
     // Note : Repurposing some Write update error codes here as specific details aren't called out for copy updates like they are
     // for write updates
     switch (src_set->descriptors_[index]->descriptor_class) {
@@ -2199,7 +2351,7 @@
                 // Validate image
                 auto image_view = img_samp_desc->GetImageView();
                 auto image_layout = img_samp_desc->GetImageLayout();
-                if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error_code, error_msg)) {
+                if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, func_name, error_code, error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted copy update to combined image sampler descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2215,7 +2367,7 @@
                 auto img_desc = static_cast<const ImageDescriptor *>(src_desc);
                 auto image_view = img_desc->GetImageView();
                 auto image_layout = img_desc->GetImageLayout();
-                if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error_code, error_msg)) {
+                if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, func_name, error_code, error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted copy update to image descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2229,7 +2381,7 @@
                 const auto src_desc = src_set->descriptors_[index + di].get();
                 if (!src_desc->updated) continue;
                 auto buffer_view = static_cast<TexelDescriptor *>(src_desc)->GetBufferView();
-                auto bv_state = GetBufferViewState(device_data_, buffer_view);
+                auto bv_state = device_data_->GetBufferViewState(buffer_view);
                 if (!bv_state) {
                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
                     std::stringstream error_str;
@@ -2238,7 +2390,7 @@
                     return false;
                 }
                 auto buffer = bv_state->create_info.buffer;
-                if (!ValidateBufferUsage(GetBufferState(device_data_, buffer), type, error_code, error_msg)) {
+                if (!ValidateBufferUsage(device_data_->GetBufferState(buffer), type, error_code, error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted copy update to texel buffer descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2252,7 +2404,7 @@
                 const auto src_desc = src_set->descriptors_[index + di].get();
                 if (!src_desc->updated) continue;
                 auto buffer = static_cast<BufferDescriptor *>(src_desc)->GetBuffer();
-                if (!ValidateBufferUsage(GetBufferState(device_data_, buffer), type, error_code, error_msg)) {
+                if (!ValidateBufferUsage(device_data_->GetBufferState(buffer), type, error_code, error_msg)) {
                     std::stringstream error_str;
                     error_str << "Attempted copy update to buffer descriptor failed due to: " << error_msg->c_str();
                     *error_msg = error_str.str();
@@ -2272,8 +2424,8 @@
     return true;
 }
 // Update the common AllocateDescriptorSetsData
-void cvdescriptorset::UpdateAllocateDescriptorSetsData(const layer_data *dev_data, const VkDescriptorSetAllocateInfo *p_alloc_info,
-                                                       AllocateDescriptorSetsData *ds_data) {
+void CoreChecks::UpdateAllocateDescriptorSetsData(const layer_data *dev_data, const VkDescriptorSetAllocateInfo *p_alloc_info,
+                                                  cvdescriptorset::AllocateDescriptorSetsData *ds_data) {
     for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
         auto layout = GetDescriptorSetLayout(dev_data, p_alloc_info->pSetLayouts[i]);
         if (layout) {
@@ -2289,22 +2441,20 @@
     }
 }
 // Verify that the state at allocate time is correct, but don't actually allocate the sets yet
-bool cvdescriptorset::ValidateAllocateDescriptorSets(const core_validation::layer_data *dev_data,
-                                                     const VkDescriptorSetAllocateInfo *p_alloc_info,
-                                                     const AllocateDescriptorSetsData *ds_data) {
+bool CoreChecks::ValidateAllocateDescriptorSets(const layer_data *dev_data, const VkDescriptorSetAllocateInfo *p_alloc_info,
+                                                const cvdescriptorset::AllocateDescriptorSetsData *ds_data) {
     bool skip = false;
-    auto report_data = core_validation::GetReportData(dev_data);
-    auto pool_state = GetDescriptorPoolState(dev_data, p_alloc_info->descriptorPool);
+    auto pool_state = GetDescriptorPoolState(p_alloc_info->descriptorPool);
 
     for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
         auto layout = GetDescriptorSetLayout(dev_data, p_alloc_info->pSetLayouts[i]);
         if (layout) {  // nullptr layout indicates no valid layout handle for this device, validated/logged in object_tracker
-            if (layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) {
+            if (layout->IsPushDescriptor()) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
                                 HandleToUint64(p_alloc_info->pSetLayouts[i]), "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-00308",
-                                "Layout 0x%" PRIxLEAST64 " specified at pSetLayouts[%" PRIu32
+                                "Layout %s specified at pSetLayouts[%" PRIu32
                                 "] in vkAllocateDescriptorSets() was created with invalid flag %s set.",
-                                HandleToUint64(p_alloc_info->pSetLayouts[i]), i,
+                                report_data->FormatHandle(p_alloc_info->pSetLayouts[i]).c_str(), i,
                                 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR");
             }
             if (layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT &&
@@ -2315,25 +2465,26 @@
             }
         }
     }
-    if (!GetDeviceExtensions(dev_data)->vk_khr_maintenance1) {
+    if (!GetDeviceExtensions()->vk_khr_maintenance1) {
         // Track number of descriptorSets allowable in this pool
         if (pool_state->availableSets < p_alloc_info->descriptorSetCount) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
                             HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorSetCount-00306",
-                            "Unable to allocate %u descriptorSets from pool 0x%" PRIxLEAST64
+                            "Unable to allocate %u descriptorSets from pool %s"
                             ". This pool only has %d descriptorSets remaining.",
-                            p_alloc_info->descriptorSetCount, HandleToUint64(pool_state->pool), pool_state->availableSets);
+                            p_alloc_info->descriptorSetCount, report_data->FormatHandle(pool_state->pool).c_str(),
+                            pool_state->availableSets);
         }
         // Determine whether descriptor counts are satisfiable
         for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
             if (ds_data->required_descriptors_by_type.at(it->first) > pool_state->availableDescriptorTypeCount[it->first]) {
-                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                                HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307",
-                                "Unable to allocate %u descriptors of type %s from pool 0x%" PRIxLEAST64
-                                ". This pool only has %d descriptors of this type remaining.",
-                                ds_data->required_descriptors_by_type.at(it->first),
-                                string_VkDescriptorType(VkDescriptorType(it->first)), HandleToUint64(pool_state->pool),
-                                pool_state->availableDescriptorTypeCount[it->first]);
+                skip |= log_msg(
+                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
+                    HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307",
+                    "Unable to allocate %u descriptors of type %s from pool %s"
+                    ". This pool only has %d descriptors of this type remaining.",
+                    ds_data->required_descriptors_by_type.at(it->first), string_VkDescriptorType(VkDescriptorType(it->first)),
+                    report_data->FormatHandle(pool_state->pool).c_str(), pool_state->availableDescriptorTypeCount[it->first]);
             }
         }
     }
@@ -2366,12 +2517,12 @@
     return skip;
 }
 // Decrement allocated sets from the pool and insert new sets into set_map
-void cvdescriptorset::PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *p_alloc_info,
-                                                    const VkDescriptorSet *descriptor_sets,
-                                                    const AllocateDescriptorSetsData *ds_data,
-                                                    std::unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> *pool_map,
-                                                    std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> *set_map,
-                                                    layer_data *dev_data) {
+void CoreChecks::PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *p_alloc_info,
+                                               const VkDescriptorSet *descriptor_sets,
+                                               const cvdescriptorset::AllocateDescriptorSetsData *ds_data,
+                                               std::unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> *pool_map,
+                                               std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> *set_map,
+                                               layer_data *dev_data) {
     auto pool_state = (*pool_map)[p_alloc_info->descriptorPool];
     // Account for sets and individual descriptors allocated from pool
     pool_state->availableSets -= p_alloc_info->descriptorSetCount;
@@ -2387,7 +2538,7 @@
         uint32_t variable_count = variable_count_valid ? variable_count_info->pDescriptorCounts[i] : 0;
 
         auto new_ds = new cvdescriptorset::DescriptorSet(descriptor_sets[i], p_alloc_info->descriptorPool, ds_data->layout_nodes[i],
-                                                         variable_count, dev_data);
+                                                         variable_count, this);
 
         pool_state->sets.insert(new_ds);
         new_ds->in_use.store(0);
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 74a3bde..012a178 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,8 +21,6 @@
 #ifndef CORE_VALIDATION_DESCRIPTOR_SETS_H_
 #define CORE_VALIDATION_DESCRIPTOR_SETS_H_
 
-#include "core_validation_error_enums.h"
-#include "core_validation_types.h"
 #include "hash_vk_types.h"
 #include "vk_layer_logging.h"
 #include "vk_layer_utils.h"
@@ -36,7 +34,8 @@
 #include <unordered_set>
 #include <vector>
 
-using core_validation::layer_data;
+class CoreChecks;
+typedef CoreChecks layer_data;
 
 // Descriptor Data structures
 namespace cvdescriptorset {
@@ -116,6 +115,7 @@
         return GetDescriptorSetLayoutBindingPtrFromIndex(GetIndexFromBinding(binding));
     }
     const std::vector<safe_VkDescriptorSetLayoutBinding> &GetBindings() const { return bindings_; }
+    const std::vector<VkDescriptorBindingFlagsEXT> &GetBindingFlags() const { return binding_flags_; }
     uint32_t GetDescriptorCountFromIndex(const uint32_t) const;
     uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const {
         return GetDescriptorCountFromIndex(GetIndexFromBinding(binding));
@@ -164,8 +164,8 @@
     const BindingTypeStats &GetBindingTypeStats() const { return binding_type_stats_; }
 
    private:
-    // Only the first two data members are used for hash and equality checks, the other members are derived from them, and are used
-    // to speed up the various lookups/queries/validations
+    // Only the first three data members are used for hash and equality checks, the other members are derived from them, and are
+    // used to speed up the various lookups/queries/validations
     VkDescriptorSetLayoutCreateFlags flags_;
     std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
     std::vector<VkDescriptorBindingFlagsEXT> binding_flags_;
@@ -185,8 +185,10 @@
     BindingTypeStats binding_type_stats_;
 };
 
-static bool operator==(const DescriptorSetLayoutDef &lhs, const DescriptorSetLayoutDef &rhs) {
-    return (lhs.GetCreateFlags() == rhs.GetCreateFlags()) && (lhs.GetBindings() == rhs.GetBindings());
+static inline bool operator==(const DescriptorSetLayoutDef &lhs, const DescriptorSetLayoutDef &rhs) {
+    bool result = (lhs.GetCreateFlags() == rhs.GetCreateFlags()) && (lhs.GetBindings() == rhs.GetBindings()) &&
+                  (lhs.GetBindingFlags() == rhs.GetBindingFlags());
+    return result;
 }
 
 // Canonical dictionary of DSL definitions -- independent of device or handle
@@ -300,7 +302,7 @@
     virtual void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) = 0;
     virtual void CopyUpdate(const Descriptor *) = 0;
     // Create binding between resources of this descriptor and given cb_node
-    virtual void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) = 0;
+    virtual void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) = 0;
     virtual DescriptorClass GetClass() const { return descriptor_class; };
     // Special fast-path check for SamplerDescriptors that are immutable
     virtual bool IsImmutableSampler() const { return false; };
@@ -313,8 +315,8 @@
 };
 // Shared helper functions - These are useful because the shared sampler image descriptor type
 //  performs common functions with both sampler and image descriptors so they can share their common functions
-bool ValidateSampler(const VkSampler, const core_validation::layer_data *);
-bool ValidateImageUpdate(VkImageView, VkImageLayout, VkDescriptorType, const core_validation::layer_data *, std::string *,
+bool ValidateSampler(const VkSampler, layer_data *);
+bool ValidateImageUpdate(VkImageView, VkImageLayout, VkDescriptorType, layer_data *, const char *func_name, std::string *,
                          std::string *);
 
 class SamplerDescriptor : public Descriptor {
@@ -322,7 +324,7 @@
     SamplerDescriptor(const VkSampler *);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsImmutableSampler() const override { return immutable_; };
     VkSampler GetSampler() const { return sampler_; }
 
@@ -337,7 +339,7 @@
     ImageSamplerDescriptor(const VkSampler *);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsImmutableSampler() const override { return immutable_; };
     VkSampler GetSampler() const { return sampler_; }
     VkImageView GetImageView() const { return image_view_; }
@@ -355,7 +357,7 @@
     ImageDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsStorage() const override { return storage_; }
     VkImageView GetImageView() const { return image_view_; }
     VkImageLayout GetImageLayout() const { return image_layout_; }
@@ -371,7 +373,7 @@
     TexelDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsStorage() const override { return storage_; }
     VkBufferView GetBufferView() const { return buffer_view_; }
 
@@ -385,7 +387,7 @@
     BufferDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override;
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsDynamic() const override { return dynamic_; }
     virtual bool IsStorage() const override { return storage_; }
     VkBuffer GetBuffer() const { return buffer_; }
@@ -408,7 +410,7 @@
     }
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; }
     void CopyUpdate(const Descriptor *) override { updated = true; }
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override {}
 };
 
 class AccelerationStructureDescriptor : public Descriptor {
@@ -419,7 +421,7 @@
     }
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; }
     void CopyUpdate(const Descriptor *) override { updated = true; }
-    void UpdateDrawState(core_validation::layer_data *, GLOBAL_CB_NODE *) override {}
+    void UpdateDrawState(layer_data *, GLOBAL_CB_NODE *) override {}
 };
 
 // Structs to contain common elements that need to be shared between Validate* and Perform* calls below
@@ -430,25 +432,18 @@
 };
 // Helper functions for descriptor set functions that cross multiple sets
 // "Validate" will make sure an update is ok without actually performing it
-bool ValidateUpdateDescriptorSets(const debug_report_data *, const core_validation::layer_data *, uint32_t,
-                                  const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *);
+bool ValidateUpdateDescriptorSets(const debug_report_data *, const layer_data *, uint32_t, const VkWriteDescriptorSet *, uint32_t,
+                                  const VkCopyDescriptorSet *, const char *func_name);
 // "Perform" does the update with the assumption that ValidateUpdateDescriptorSets() has passed for the given update
-void PerformUpdateDescriptorSets(const core_validation::layer_data *, uint32_t, const VkWriteDescriptorSet *, uint32_t,
-                                 const VkCopyDescriptorSet *);
-// Similar to PerformUpdateDescriptorSets, this function will do the same for updating via templates
-void PerformUpdateDescriptorSetsWithTemplateKHR(layer_data *, VkDescriptorSet, std::unique_ptr<TEMPLATE_STATE> const &,
-                                                const void *);
-// Update the common AllocateDescriptorSetsData struct which can then be shared between Validate* and Perform* funcs below
-void UpdateAllocateDescriptorSetsData(const layer_data *dev_data, const VkDescriptorSetAllocateInfo *,
-                                      AllocateDescriptorSetsData *);
-// Validate that Allocation state is ok
-bool ValidateAllocateDescriptorSets(const core_validation::layer_data *, const VkDescriptorSetAllocateInfo *,
-                                    const AllocateDescriptorSetsData *);
-// Update state based on allocating new descriptorsets
-void PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *, const VkDescriptorSet *, const AllocateDescriptorSetsData *,
-                                   std::unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> *,
-                                   std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> *,
-                                   core_validation::layer_data *);
+void PerformUpdateDescriptorSets(layer_data *, uint32_t, const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *);
+
+// Helper class to encapsulate the descriptor update template decoding logic
+struct DecodedTemplateUpdate {
+    std::vector<VkWriteDescriptorSet> desc_writes;
+    std::vector<VkWriteDescriptorSetInlineUniformBlockEXT> inline_infos;
+    DecodedTemplateUpdate(layer_data *device_data, VkDescriptorSet descriptorSet, const TEMPLATE_STATE *template_state,
+                          const void *pData, VkDescriptorSetLayout push_layout = VK_NULL_HANDLE);
+};
 
 /*
  * DescriptorSet class
@@ -471,7 +466,7 @@
 class DescriptorSet : public BASE_NODE {
    public:
     DescriptorSet(const VkDescriptorSet, const VkDescriptorPool, const std::shared_ptr<DescriptorSetLayout const> &,
-                  uint32_t variable_count, core_validation::layer_data *);
+                  uint32_t variable_count, layer_data *);
     ~DescriptorSet();
     // A number of common Get* functions that return data based on layout from which this set was created
     uint32_t GetTotalDescriptorCount() const { return p_layout_->GetTotalDescriptorCount(); };
@@ -500,14 +495,20 @@
     uint32_t GetStorageUpdates(const std::map<uint32_t, descriptor_req> &, std::unordered_set<VkBuffer> *,
                                std::unordered_set<VkImageView> *) const;
 
+    std::string StringifySetAndLayout() const;
     // Descriptor Update functions. These functions validate state and perform update separately
+    // Validate contents of a push descriptor update
+    bool ValidatePushDescriptorsUpdate(const debug_report_data *report_data, uint32_t write_count,
+                                       const VkWriteDescriptorSet *p_wds, const char *func_name);
+    // Perform a push update whose contents were just validated using ValidatePushDescriptorsUpdate
+    void PerformPushDescriptorsUpdate(uint32_t write_count, const VkWriteDescriptorSet *p_wds);
     // Validate contents of a WriteUpdate
-    bool ValidateWriteUpdate(const debug_report_data *, const VkWriteDescriptorSet *, std::string *, std::string *);
+    bool ValidateWriteUpdate(const debug_report_data *, const VkWriteDescriptorSet *, const char *, std::string *, std::string *);
     // Perform a WriteUpdate whose contents were just validated using ValidateWriteUpdate
     void PerformWriteUpdate(const VkWriteDescriptorSet *);
     // Validate contents of a CopyUpdate
-    bool ValidateCopyUpdate(const debug_report_data *, const VkCopyDescriptorSet *, const DescriptorSet *, std::string *,
-                            std::string *);
+    bool ValidateCopyUpdate(const debug_report_data *, const VkCopyDescriptorSet *, const DescriptorSet *, const char *func_name,
+                            std::string *, std::string *);
     // Perform a CopyUpdate whose contents were just validated using ValidateCopyUpdate
     void PerformCopyUpdate(const VkCopyDescriptorSet *, const DescriptorSet *);
 
@@ -553,11 +554,11 @@
     DESCRIPTOR_POOL_STATE *GetPoolState() const { return pool_state_; }
 
    private:
-    bool VerifyWriteUpdateContents(const VkWriteDescriptorSet *, const uint32_t, std::string *, std::string *) const;
-    bool VerifyCopyUpdateContents(const VkCopyDescriptorSet *, const DescriptorSet *, VkDescriptorType, uint32_t, std::string *,
-                                  std::string *) const;
+    bool VerifyWriteUpdateContents(const VkWriteDescriptorSet *, const uint32_t, const char *, std::string *, std::string *) const;
+    bool VerifyCopyUpdateContents(const VkCopyDescriptorSet *, const DescriptorSet *, VkDescriptorType, uint32_t, const char *,
+                                  std::string *, std::string *) const;
     bool ValidateBufferUsage(BUFFER_STATE const *, VkDescriptorType, std::string *, std::string *) const;
-    bool ValidateBufferUpdate(VkDescriptorBufferInfo const *, VkDescriptorType, std::string *, std::string *) const;
+    bool ValidateBufferUpdate(VkDescriptorBufferInfo const *, VkDescriptorType, const char *, std::string *, std::string *) const;
     // Private helper to set all bound cmd buffers to INVALID state
     void InvalidateBoundCmdBuffers();
     bool some_update_;  // has any part of the set ever been updated?
@@ -565,8 +566,7 @@
     DESCRIPTOR_POOL_STATE *pool_state_;
     const std::shared_ptr<DescriptorSetLayout const> p_layout_;
     std::vector<std::unique_ptr<Descriptor>> descriptors_;
-    // Ptr to device data used for various data look-ups
-    core_validation::layer_data *const device_data_;
+    layer_data *device_data_;
     const VkPhysicalDeviceLimits limits_;
     uint32_t variable_count_;
 
diff --git a/layers/gpu_validation.cpp b/layers/gpu_validation.cpp
new file mode 100644
index 0000000..6ec10c5
--- /dev/null
+++ b/layers/gpu_validation.cpp
@@ -0,0 +1,1215 @@
+/* Copyright (c) 2018-2019 The Khronos Group Inc.
+ * Copyright (c) 2018-2019 Valve Corporation
+ * Copyright (c) 2018-2019 LunarG, Inc.
+ * Copyright (C) 2018-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Allow use of STL min and max functions in Windows
+#define NOMINMAX
+
+#include "chassis.h"
+#include "core_validation.h"
+#include "gpu_validation.h"
+#include "shader_validation.h"
+#include "spirv-tools/libspirv.h"
+#include "spirv-tools/optimizer.hpp"
+#include "spirv-tools/instrument.hpp"
+#include <SPIRV/spirv.hpp>
+#include <algorithm>
+#include <regex>
+
+// This is the number of bindings in the debug descriptor set.
+static const uint32_t kNumBindingsInSet = 1;
+
+// Implementation for Device Memory Manager class
+GpuDeviceMemoryManager::GpuDeviceMemoryManager(layer_data *dev_data, uint32_t data_size) {
+    uint32_t align = static_cast<uint32_t>(dev_data->GetPDProperties()->limits.minStorageBufferOffsetAlignment);
+    if (0 == align) {
+        align = 1;
+    }
+    record_size_ = data_size;
+    // Round the requested size up to the next multiple of the storage buffer offset alignment
+    // so that we can address each block in the storage buffer using the offset.
+    block_size_ = ((record_size_ + align - 1) / align) * align;
+    blocks_per_chunk_ = kItemsPerChunk;
+    chunk_size_ = blocks_per_chunk_ * block_size_;
+    dev_data_ = dev_data;
+}
+
+GpuDeviceMemoryManager::~GpuDeviceMemoryManager() {
+    for (auto &chunk : chunk_list_) {
+        FreeMemoryChunk(chunk);
+    }
+    chunk_list_.clear();
+}
+
+VkResult GpuDeviceMemoryManager::GetBlock(GpuDeviceMemoryBlock *block) {
+    assert(block->buffer == VK_NULL_HANDLE);  // avoid possible overwrite/leak of an allocated block
+    VkResult result = VK_SUCCESS;
+    MemoryChunk *pChunk = nullptr;
+    // Look for a chunk with available offsets.
+    for (auto &chunk : chunk_list_) {
+        if (!chunk.available_offsets.empty()) {
+            pChunk = &chunk;
+            break;
+        }
+    }
+    // If no chunks with available offsets, allocate device memory and set up offsets.
+    if (pChunk == nullptr) {
+        MemoryChunk new_chunk;
+        result = AllocMemoryChunk(new_chunk);
+        if (result == VK_SUCCESS) {
+            new_chunk.available_offsets.resize(blocks_per_chunk_);
+            for (uint32_t offset = 0, i = 0; i < blocks_per_chunk_; offset += block_size_, ++i) {
+                new_chunk.available_offsets[i] = offset;
+            }
+            chunk_list_.push_front(std::move(new_chunk));
+            pChunk = &chunk_list_.front();
+        } else {
+            // Indicate failure
+            block->buffer = VK_NULL_HANDLE;
+            block->memory = VK_NULL_HANDLE;
+            return result;
+        }
+    }
+    // Give the requester an available offset
+    block->buffer = pChunk->buffer;
+    block->memory = pChunk->memory;
+    block->offset = pChunk->available_offsets.back();
+    pChunk->available_offsets.pop_back();
+    return result;
+}
+
+void GpuDeviceMemoryManager::PutBackBlock(VkBuffer buffer, VkDeviceMemory memory, uint32_t offset) {
+    GpuDeviceMemoryBlock block = {buffer, memory, offset};
+    PutBackBlock(block);
+}
+
+void GpuDeviceMemoryManager::PutBackBlock(GpuDeviceMemoryBlock &block) {
+    // Find the chunk belonging to the allocated offset and make the offset available again
+    auto chunk = std::find_if(std::begin(chunk_list_), std::end(chunk_list_),
+                              [&block](const MemoryChunk &c) { return c.buffer == block.buffer; });
+    if (chunk_list_.end() == chunk) {
+        assert(false);
+    } else {
+        chunk->available_offsets.push_back(block.offset);
+        if (chunk->available_offsets.size() == blocks_per_chunk_) {
+            // All offsets have been returned
+            FreeMemoryChunk(*chunk);
+            chunk_list_.erase(chunk);
+        }
+    }
+}
+
+void ResetBlock(GpuDeviceMemoryBlock &block) {
+    block.buffer = VK_NULL_HANDLE;
+    block.memory = VK_NULL_HANDLE;
+    block.offset = 0;
+}
+
+bool BlockUsed(GpuDeviceMemoryBlock &block) { return (block.buffer != VK_NULL_HANDLE) && (block.memory != VK_NULL_HANDLE); }
+
+bool GpuDeviceMemoryManager::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) {
+    // Search memtypes to find first index with those properties
+    const VkPhysicalDeviceMemoryProperties *props = dev_data_->GetPhysicalDeviceMemoryProperties();
+    for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
+        if ((typeBits & 1) == 1) {
+            // Type is available, does it match user properties?
+            if ((props->memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) {
+                *typeIndex = i;
+                return true;
+            }
+        }
+        typeBits >>= 1;
+    }
+    // No memory types matched, return failure
+    return false;
+}
+
+VkResult GpuDeviceMemoryManager::AllocMemoryChunk(MemoryChunk &chunk) {
+    VkBuffer buffer;
+    VkDeviceMemory memory;
+    VkBufferCreateInfo buffer_create_info = {};
+    VkMemoryRequirements mem_reqs = {};
+    VkMemoryAllocateInfo mem_alloc = {};
+    VkResult result = VK_SUCCESS;
+    bool pass;
+    void *pData;
+    const auto *dispatch_table = dev_data_->GetDispatchTable();
+
+    buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+    buffer_create_info.size = chunk_size_;
+    result = dispatch_table->CreateBuffer(dev_data_->GetDevice(), &buffer_create_info, NULL, &buffer);
+    if (result != VK_SUCCESS) {
+        return result;
+    }
+
+    dispatch_table->GetBufferMemoryRequirements(dev_data_->GetDevice(), buffer, &mem_reqs);
+
+    mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mem_alloc.pNext = NULL;
+    mem_alloc.allocationSize = mem_reqs.size;
+    pass = MemoryTypeFromProperties(mem_reqs.memoryTypeBits,
+                                    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+                                    &mem_alloc.memoryTypeIndex);
+    if (!pass) {
+        dispatch_table->DestroyBuffer(dev_data_->GetDevice(), buffer, NULL);
+        return result;
+    }
+    result = dispatch_table->AllocateMemory(dev_data_->GetDevice(), &mem_alloc, NULL, &memory);
+    if (result != VK_SUCCESS) {
+        dispatch_table->DestroyBuffer(dev_data_->GetDevice(), buffer, NULL);
+        return result;
+    }
+
+    result = dispatch_table->BindBufferMemory(dev_data_->GetDevice(), buffer, memory, 0);
+    if (result != VK_SUCCESS) {
+        dispatch_table->DestroyBuffer(dev_data_->GetDevice(), buffer, NULL);
+        dispatch_table->FreeMemory(dev_data_->GetDevice(), memory, NULL);
+        return result;
+    }
+
+    result = dispatch_table->MapMemory(dev_data_->GetDevice(), memory, 0, mem_alloc.allocationSize, 0, &pData);
+    if (result == VK_SUCCESS) {
+        memset(pData, 0, chunk_size_);
+        dispatch_table->UnmapMemory(dev_data_->GetDevice(), memory);
+    } else {
+        dispatch_table->DestroyBuffer(dev_data_->GetDevice(), buffer, NULL);
+        dispatch_table->FreeMemory(dev_data_->GetDevice(), memory, NULL);
+        return result;
+    }
+    chunk.buffer = buffer;
+    chunk.memory = memory;
+    return result;
+}
+
+void GpuDeviceMemoryManager::FreeMemoryChunk(MemoryChunk &chunk) {
+    dev_data_->GetDispatchTable()->DestroyBuffer(dev_data_->GetDevice(), chunk.buffer, NULL);
+    dev_data_->GetDispatchTable()->FreeMemory(dev_data_->GetDevice(), chunk.memory, NULL);
+}
+
+void GpuDeviceMemoryManager::FreeAllBlocks() {
+    for (auto &chunk : chunk_list_) {
+        FreeMemoryChunk(chunk);
+    }
+    chunk_list_.clear();
+}
+
+// Implementation for Descriptor Set Manager class
+GpuDescriptorSetManager::GpuDescriptorSetManager(layer_data *dev_data) { dev_data_ = dev_data; }
+
+GpuDescriptorSetManager::~GpuDescriptorSetManager() {
+    for (auto &pool : desc_pool_map_) {
+        dev_data_->GetDispatchTable()->DestroyDescriptorPool(dev_data_->GetDevice(), pool.first, NULL);
+    }
+    desc_pool_map_.clear();
+}
+
+VkResult GpuDescriptorSetManager::GetDescriptorSets(uint32_t count, VkDescriptorPool *pool,
+                                                    std::vector<VkDescriptorSet> *desc_sets) {
+    auto gpu_state = dev_data_->GetGpuValidationState();
+    const uint32_t default_pool_size = kItemsPerChunk;
+    VkResult result = VK_SUCCESS;
+    VkDescriptorPool pool_to_use = VK_NULL_HANDLE;
+
+    if (0 == count) {
+        return result;
+    }
+    desc_sets->clear();
+    desc_sets->resize(count);
+
+    for (auto &pool : desc_pool_map_) {
+        if (pool.second.used + count < pool.second.size) {
+            pool_to_use = pool.first;
+            break;
+        }
+    }
+    if (VK_NULL_HANDLE == pool_to_use) {
+        uint32_t pool_count = default_pool_size;
+        if (count > default_pool_size) {
+            pool_count = count;
+        }
+        const VkDescriptorPoolSize size_counts = {
+            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+            pool_count * kNumBindingsInSet,
+        };
+        VkDescriptorPoolCreateInfo desc_pool_info = {};
+        desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+        desc_pool_info.pNext = NULL;
+        desc_pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
+        desc_pool_info.maxSets = pool_count;
+        desc_pool_info.poolSizeCount = 1;
+        desc_pool_info.pPoolSizes = &size_counts;
+        result = dev_data_->GetDispatchTable()->CreateDescriptorPool(dev_data_->GetDevice(), &desc_pool_info, NULL, &pool_to_use);
+        assert(result == VK_SUCCESS);
+        if (result != VK_SUCCESS) {
+            return result;
+        }
+        desc_pool_map_[pool_to_use].size = desc_pool_info.maxSets;
+        desc_pool_map_[pool_to_use].used = 0;
+    }
+    std::vector<VkDescriptorSetLayout> desc_layouts(count, gpu_state->debug_desc_layout);
+
+    VkDescriptorSetAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, NULL, pool_to_use, count,
+                                              desc_layouts.data()};
+
+    result = dev_data_->GetDispatchTable()->AllocateDescriptorSets(dev_data_->GetDevice(), &alloc_info, desc_sets->data());
+    assert(result == VK_SUCCESS);
+    if (result != VK_SUCCESS) {
+        return result;
+    }
+    *pool = pool_to_use;
+    desc_pool_map_[pool_to_use].used += count;
+    return result;
+}
+
+void GpuDescriptorSetManager::PutBackDescriptorSet(VkDescriptorPool desc_pool, VkDescriptorSet desc_set) {
+    auto iter = desc_pool_map_.find(desc_pool);
+    if (iter != desc_pool_map_.end()) {
+        VkResult result = dev_data_->GetDispatchTable()->FreeDescriptorSets(dev_data_->GetDevice(), desc_pool, 1, &desc_set);
+        assert(result == VK_SUCCESS);
+        if (result != VK_SUCCESS) {
+            return;
+        }
+        desc_pool_map_[desc_pool].used--;
+        if (0 == desc_pool_map_[desc_pool].used) {
+            dev_data_->GetDispatchTable()->DestroyDescriptorPool(dev_data_->GetDevice(), desc_pool, NULL);
+            desc_pool_map_.erase(desc_pool);
+        }
+    }
+    return;
+}
+
+void GpuDescriptorSetManager::DestroyDescriptorPools() {
+    for (auto &pool : desc_pool_map_) {
+        dev_data_->GetDispatchTable()->DestroyDescriptorPool(dev_data_->GetDevice(), pool.first, NULL);
+    }
+    desc_pool_map_.clear();
+}
+
+// Convenience function for reporting problems with setting up GPU Validation.
+void CoreChecks::ReportSetupProblem(const layer_data *dev_data, VkDebugReportObjectTypeEXT object_type, uint64_t object_handle,
+                                    const char *const specific_message) {
+    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, "UNASSIGNED-GPU-Assisted Validation Error. ",
+            "Detail: (%s)", specific_message);
+}
+
+// Turn on necessary device features.
+void CoreChecks::GpuPreCallRecordCreateDevice(VkPhysicalDevice gpu, std::unique_ptr<safe_VkDeviceCreateInfo> &create_info,
+                                              VkPhysicalDeviceFeatures *supported_features) {
+    if (supported_features->fragmentStoresAndAtomics || supported_features->vertexPipelineStoresAndAtomics) {
+        VkPhysicalDeviceFeatures new_features = {};
+        if (create_info->pEnabledFeatures) {
+            new_features = *create_info->pEnabledFeatures;
+        }
+        new_features.fragmentStoresAndAtomics = supported_features->fragmentStoresAndAtomics;
+        new_features.vertexPipelineStoresAndAtomics = supported_features->vertexPipelineStoresAndAtomics;
+        delete create_info->pEnabledFeatures;
+        create_info->pEnabledFeatures = new VkPhysicalDeviceFeatures(new_features);
+    }
+}
+
+// Perform initializations that can be done at Create Device time.
+void CoreChecks::GpuPostCallRecordCreateDevice(layer_data *dev_data) {
+    auto gpu_state = GetGpuValidationState();
+    const auto *dispatch_table = GetDispatchTable();
+
+    gpu_state->aborted = false;
+    gpu_state->reserve_binding_slot = false;
+    gpu_state->barrier_command_pool = VK_NULL_HANDLE;
+    gpu_state->barrier_command_buffer = VK_NULL_HANDLE;
+
+    if (GetPDProperties()->apiVersion < VK_API_VERSION_1_1) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "GPU-Assisted validation requires Vulkan 1.1 or later.  GPU-Assisted Validation disabled.");
+        gpu_state->aborted = true;
+        return;
+    }
+    // Some devices have extremely high limits here, so set a reasonable max because we have to pad
+    // the pipeline layout with dummy descriptor set layouts.
+    gpu_state->adjusted_max_desc_sets = GetPDProperties()->limits.maxBoundDescriptorSets;
+    gpu_state->adjusted_max_desc_sets = std::min(33U, gpu_state->adjusted_max_desc_sets);
+
+    // We can't do anything if there is only one.
+    // Device probably not a legit Vulkan device, since there should be at least 4. Protect ourselves.
+    if (gpu_state->adjusted_max_desc_sets == 1) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Device can bind only a single descriptor set.  GPU-Assisted Validation disabled.");
+        gpu_state->aborted = true;
+        return;
+    }
+    gpu_state->desc_set_bind_index = gpu_state->adjusted_max_desc_sets - 1;
+    log_msg(GetReportData(), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+            HandleToUint64(GetDevice()), "UNASSIGNED-GPU-Assisted Validation. ", "Shaders using descriptor set at index %d. ",
+            gpu_state->desc_set_bind_index);
+
+    std::unique_ptr<GpuDeviceMemoryManager> memory_manager(
+        new GpuDeviceMemoryManager(dev_data, sizeof(uint32_t) * (spvtools::kInstMaxOutCnt + 1)));
+    std::unique_ptr<GpuDescriptorSetManager> desc_set_manager(new GpuDescriptorSetManager(dev_data));
+
+    // The descriptor indexing checks require only the first "output" binding.
+    const VkDescriptorSetLayoutBinding debug_desc_layout_bindings[kNumBindingsInSet] = {
+        {
+            0,  // output
+            VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+            1,
+            VK_SHADER_STAGE_ALL_GRAPHICS,
+            NULL,
+        },
+    };
+
+    const VkDescriptorSetLayoutCreateInfo debug_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0,
+                                                                    kNumBindingsInSet, debug_desc_layout_bindings};
+
+    const VkDescriptorSetLayoutCreateInfo dummy_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, 0,
+                                                                    NULL};
+
+    VkResult result =
+        dispatch_table->CreateDescriptorSetLayout(GetDevice(), &debug_desc_layout_info, NULL, &gpu_state->debug_desc_layout);
+
+    // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index.
+    VkResult result2 =
+        dispatch_table->CreateDescriptorSetLayout(GetDevice(), &dummy_desc_layout_info, NULL, &gpu_state->dummy_desc_layout);
+    assert((result == VK_SUCCESS) && (result2 == VK_SUCCESS));
+    if ((result != VK_SUCCESS) || (result2 != VK_SUCCESS)) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unable to create descriptor set layout.  GPU-Assisted Validation disabled.");
+        if (result == VK_SUCCESS) {
+            dispatch_table->DestroyDescriptorSetLayout(GetDevice(), gpu_state->debug_desc_layout, NULL);
+        }
+        if (result2 == VK_SUCCESS) {
+            dispatch_table->DestroyDescriptorSetLayout(GetDevice(), gpu_state->dummy_desc_layout, NULL);
+        }
+        gpu_state->debug_desc_layout = VK_NULL_HANDLE;
+        gpu_state->dummy_desc_layout = VK_NULL_HANDLE;
+        gpu_state->aborted = true;
+        return;
+    }
+    gpu_state->memory_manager = std::move(memory_manager);
+    gpu_state->desc_set_manager = std::move(desc_set_manager);
+}
+
+// Clean up device-related resources
+void CoreChecks::GpuPreCallRecordDestroyDevice(layer_data *dev_data) {
+    auto gpu_state = GetGpuValidationState();
+
+    if (gpu_state->barrier_command_buffer) {
+        GetDispatchTable()->FreeCommandBuffers(GetDevice(), gpu_state->barrier_command_pool, 1, &gpu_state->barrier_command_buffer);
+        gpu_state->barrier_command_buffer = VK_NULL_HANDLE;
+    }
+    if (gpu_state->barrier_command_pool) {
+        GetDispatchTable()->DestroyCommandPool(GetDevice(), gpu_state->barrier_command_pool, NULL);
+        gpu_state->barrier_command_pool = VK_NULL_HANDLE;
+    }
+    if (gpu_state->debug_desc_layout) {
+        GetDispatchTable()->DestroyDescriptorSetLayout(GetDevice(), gpu_state->debug_desc_layout, NULL);
+        gpu_state->debug_desc_layout = VK_NULL_HANDLE;
+    }
+    if (gpu_state->dummy_desc_layout) {
+        GetDispatchTable()->DestroyDescriptorSetLayout(GetDevice(), gpu_state->dummy_desc_layout, NULL);
+        gpu_state->dummy_desc_layout = VK_NULL_HANDLE;
+    }
+    gpu_state->memory_manager->FreeAllBlocks();
+    gpu_state->desc_set_manager->DestroyDescriptorPools();
+}
+
+// Modify the pipeline layout to include our debug descriptor set and any needed padding with the dummy descriptor set.
+bool CoreChecks::GpuPreCallCreatePipelineLayout(layer_data *device_data, const VkPipelineLayoutCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
+                                                std::vector<VkDescriptorSetLayout> *new_layouts,
+                                                VkPipelineLayoutCreateInfo *modified_create_info) {
+    auto gpu_state = GetGpuValidationState();
+    if (gpu_state->aborted) {
+        return false;
+    }
+
+    if (modified_create_info->setLayoutCount >= gpu_state->adjusted_max_desc_sets) {
+        std::ostringstream strm;
+        strm << "Pipeline Layout conflict with validation's descriptor set at slot " << gpu_state->desc_set_bind_index << ". "
+             << "Application has too many descriptor sets in the pipeline layout to continue with gpu validation. "
+             << "Validation is not modifying the pipeline layout. "
+             << "Instrumented shaders are replaced with non-instrumented shaders.";
+        ReportSetupProblem(device_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()), strm.str().c_str());
+    } else {
+        // Modify the pipeline layout by:
+        // 1. Copying the caller's descriptor set desc_layouts
+        // 2. Fill in dummy descriptor layouts up to the max binding
+        // 3. Fill in with the debug descriptor layout at the max binding slot
+        new_layouts->reserve(gpu_state->adjusted_max_desc_sets);
+        new_layouts->insert(new_layouts->end(), &pCreateInfo->pSetLayouts[0],
+                            &pCreateInfo->pSetLayouts[pCreateInfo->setLayoutCount]);
+        for (uint32_t i = pCreateInfo->setLayoutCount; i < gpu_state->adjusted_max_desc_sets - 1; ++i) {
+            new_layouts->push_back(gpu_state->dummy_desc_layout);
+        }
+        new_layouts->push_back(gpu_state->debug_desc_layout);
+        modified_create_info->pSetLayouts = new_layouts->data();
+        modified_create_info->setLayoutCount = gpu_state->adjusted_max_desc_sets;
+    }
+    return true;
+}
+
+// Clean up GPU validation after the CreatePipelineLayout call is made
+void CoreChecks::GpuPostCallCreatePipelineLayout(layer_data *device_data, VkResult result) {
+    auto gpu_state = GetGpuValidationState();
+    // Clean up GPU validation
+    if (result != VK_SUCCESS) {
+        ReportSetupProblem(device_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unable to create pipeline layout.  Device could become unstable.");
+        gpu_state->aborted = true;
+    }
+}
+
+// Free the device memory and descriptor set associated with a command buffer.
+void CoreChecks::GpuPreCallRecordFreeCommandBuffers(layer_data *dev_data, uint32_t commandBufferCount,
+                                                    const VkCommandBuffer *pCommandBuffers) {
+    auto gpu_state = GetGpuValidationState();
+    if (gpu_state->aborted) {
+        return;
+    }
+    for (uint32_t i = 0; i < commandBufferCount; ++i) {
+        auto cb_node = GetCBNode(pCommandBuffers[i]);
+        if (cb_node) {
+            for (auto &buffer_info : cb_node->gpu_buffer_list) {
+                if (BlockUsed(buffer_info.mem_block)) {
+                    gpu_state->memory_manager->PutBackBlock(buffer_info.mem_block);
+                    ResetBlock(buffer_info.mem_block);
+                }
+                if (buffer_info.desc_set != VK_NULL_HANDLE) {
+                    gpu_state->desc_set_manager->PutBackDescriptorSet(buffer_info.desc_pool, buffer_info.desc_set);
+                }
+            }
+            cb_node->gpu_buffer_list.clear();
+        }
+    }
+}
+
+// Just gives a warning about a possible deadlock.
+void CoreChecks::GpuPreCallValidateCmdWaitEvents(layer_data *dev_data, VkPipelineStageFlags sourceStageMask) {
+    if (sourceStageMask & VK_PIPELINE_STAGE_HOST_BIT) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "CmdWaitEvents recorded with VK_PIPELINE_STAGE_HOST_BIT set. "
+                           "GPU_Assisted validation waits on queue completion. "
+                           "This wait could block the host's signaling of this event, resulting in deadlock.");
+    }
+}
+
+// Examine the pipelines to see if they use the debug descriptor set binding index.
+// If any do, create new non-instrumented shader modules and use them to replace the instrumented
+// shaders in the pipeline.  Return the (possibly) modified create infos to the caller.
+std::vector<safe_VkGraphicsPipelineCreateInfo> CoreChecks::GpuPreCallRecordCreateGraphicsPipelines(
+    layer_data *dev_data, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo *pCreateInfos,
+    const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines, std::vector<std::unique_ptr<PIPELINE_STATE>> &pipe_state) {
+    auto gpu_state = GetGpuValidationState();
+
+    std::vector<safe_VkGraphicsPipelineCreateInfo> new_pipeline_create_infos;
+    std::vector<unsigned int> pipeline_uses_debug_index(count);
+
+    // Walk through all the pipelines, make a copy of each and flag each pipeline that contains a shader that uses the debug
+    // descriptor set index.
+    for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
+        new_pipeline_create_infos.push_back(pipe_state[pipeline]->graphicsPipelineCI);
+        if (pipe_state[pipeline]->active_slots.find(gpu_state->desc_set_bind_index) != pipe_state[pipeline]->active_slots.end()) {
+            pipeline_uses_debug_index[pipeline] = 1;
+        }
+    }
+
+    // See if any pipeline has shaders using the debug descriptor set index
+    if (std::all_of(pipeline_uses_debug_index.begin(), pipeline_uses_debug_index.end(), [](unsigned int i) { return i == 0; })) {
+        // None of the shaders in all the pipelines use the debug descriptor set index, so use the pipelines
+        // as they stand with the instrumented shaders.
+        return new_pipeline_create_infos;
+    }
+
+    // At least one pipeline has a shader that uses the debug descriptor set index.
+    for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
+        if (pipeline_uses_debug_index[pipeline]) {
+            for (uint32_t stage = 0; stage < pCreateInfos[pipeline].stageCount; ++stage) {
+                const shader_module *shader = GetShaderModuleState(pCreateInfos[pipeline].pStages[stage].module);
+                VkShaderModuleCreateInfo create_info = {};
+                VkShaderModule shader_module;
+                create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+                create_info.pCode = shader->words.data();
+                create_info.codeSize = shader->words.size() * sizeof(uint32_t);
+                VkResult result = GetDispatchTable()->CreateShaderModule(GetDevice(), &create_info, pAllocator, &shader_module);
+                if (result == VK_SUCCESS) {
+                    new_pipeline_create_infos[pipeline].pStages[stage].module = shader_module;
+                } else {
+                    ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                                       HandleToUint64(pCreateInfos[pipeline].pStages[stage].module),
+                                       "Unable to replace instrumented shader with non-instrumented one.  "
+                                       "Device could become unstable.");
+                }
+            }
+        }
+    }
+    return new_pipeline_create_infos;
+}
+
+// For every pipeline:
+// - For every shader in a pipeline:
+//   - If the shader had to be replaced in PreCallRecord (because the pipeline is using the debug desc set index):
+//     - Destroy it since it has been bound into the pipeline by now.  This is our only chance to delete it.
+//   - Track the shader in the shader_map
+//   - Save the shader binary if it contains debug code
+void CoreChecks::GpuPostCallRecordCreateGraphicsPipelines(layer_data *dev_data, const uint32_t count,
+                                                          const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                          const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
+    auto gpu_state = GetGpuValidationState();
+    for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
+        auto pipeline_state = GetPipelineState(pPipelines[pipeline]);
+        if (nullptr == pipeline_state) continue;
+        for (uint32_t stage = 0; stage < pipeline_state->graphicsPipelineCI.stageCount; ++stage) {
+            if (pipeline_state->active_slots.find(gpu_state->desc_set_bind_index) != pipeline_state->active_slots.end()) {
+                GetDispatchTable()->DestroyShaderModule(GetDevice(), pCreateInfos->pStages[stage].module, pAllocator);
+            }
+            auto shader_state = GetShaderModuleState(pipeline_state->graphicsPipelineCI.pStages[stage].module);
+            std::vector<unsigned int> code;
+            // Save the shader binary if debug info is present.
+            // The core_validation ShaderModule tracker saves the binary too, but discards it when the ShaderModule
+            // is destroyed.  Applications may destroy ShaderModules after they are placed in a pipeline and before
+            // the pipeline is used, so we have to keep another copy.
+            if (shader_state && shader_state->has_valid_spirv) {  // really checking for presense of SPIR-V code.
+                for (auto insn : *shader_state) {
+                    if (insn.opcode() == spv::OpLine) {
+                        code = shader_state->words;
+                        break;
+                    }
+                }
+            }
+            gpu_state->shader_map[shader_state->gpu_validation_shader_id].pipeline = pipeline_state->pipeline;
+            // Be careful to use the originally bound (instrumented) shader here, even if PreCallRecord had to back it
+            // out with a non-instrumented shader.  The non-instrumented shader (found in pCreateInfo) was destroyed above.
+            gpu_state->shader_map[shader_state->gpu_validation_shader_id].shader_module =
+                pipeline_state->graphicsPipelineCI.pStages[stage].module;
+            gpu_state->shader_map[shader_state->gpu_validation_shader_id].pgm = std::move(code);
+        }
+    }
+}
+
+// Remove all the shader trackers associated with this destroyed pipeline.
+void CoreChecks::GpuPreCallRecordDestroyPipeline(layer_data *dev_data, const VkPipeline pipeline) {
+    auto gpu_state = GetGpuValidationState();
+    for (auto it = gpu_state->shader_map.begin(); it != gpu_state->shader_map.end();) {
+        if (it->second.pipeline == pipeline) {
+            it = gpu_state->shader_map.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+// Call the SPIR-V Optimizer to run the instrumentation pass on the shader.
+bool CoreChecks::GpuInstrumentShader(layer_data *dev_data, const VkShaderModuleCreateInfo *pCreateInfo,
+                                     std::vector<unsigned int> &new_pgm, uint32_t *unique_shader_id) {
+    auto gpu_state = GetGpuValidationState();
+    if (gpu_state->aborted) return false;
+    if (pCreateInfo->pCode[0] != spv::MagicNumber) return false;
+
+    // Load original shader SPIR-V
+    uint32_t num_words = static_cast<uint32_t>(pCreateInfo->codeSize / 4);
+    new_pgm.clear();
+    new_pgm.reserve(num_words);
+    new_pgm.insert(new_pgm.end(), &pCreateInfo->pCode[0], &pCreateInfo->pCode[num_words]);
+
+    // Call the optimizer to instrument the shader.
+    // Use the unique_shader_module_id as a shader ID so we can look up its handle later in the shader_map.
+    using namespace spvtools;
+    spv_target_env target_env = SPV_ENV_VULKAN_1_1;
+    Optimizer optimizer(target_env);
+    optimizer.RegisterPass(CreateInstBindlessCheckPass(gpu_state->desc_set_bind_index, gpu_state->unique_shader_module_id));
+    optimizer.RegisterPass(CreateAggressiveDCEPass());
+    bool pass = optimizer.Run(new_pgm.data(), new_pgm.size(), &new_pgm);
+    if (!pass) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT, VK_NULL_HANDLE,
+                           "Failure to instrument shader.  Proceeding with non-instrumented shader.");
+    }
+    *unique_shader_id = gpu_state->unique_shader_module_id++;
+    return pass;
+}
+
+// Create the instrumented shader data to provide to the driver.
+bool CoreChecks::GpuPreCallCreateShaderModule(layer_data *dev_data, const VkShaderModuleCreateInfo *pCreateInfo,
+                                              const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
+                                              uint32_t *unique_shader_id, VkShaderModuleCreateInfo *instrumented_create_info,
+                                              std::vector<unsigned int> *instrumented_pgm) {
+    bool pass = GpuInstrumentShader(dev_data, pCreateInfo, *instrumented_pgm, unique_shader_id);
+    if (pass) {
+        instrumented_create_info->pCode = instrumented_pgm->data();
+        instrumented_create_info->codeSize = instrumented_pgm->size() * sizeof(unsigned int);
+    }
+    return pass;
+}
+
+// Generate the stage-specific part of the message.
+static void GenerateStageMessage(const uint32_t *debug_record, std::string &msg) {
+    using namespace spvtools;
+    std::ostringstream strm;
+    switch (debug_record[kInstCommonOutStageIdx]) {
+        case 0: {
+            strm << "Stage = Vertex. Vertex Index = " << debug_record[kInstVertOutVertexIndex]
+                 << " Instance Index = " << debug_record[kInstVertOutInstanceIndex] << ". ";
+        } break;
+        case 1: {
+            strm << "Stage = Tessellation Control.  Invocation ID = " << debug_record[kInstTessOutInvocationId] << ". ";
+        } break;
+        case 2: {
+            strm << "Stage = Tessellation Eval.  Invocation ID = " << debug_record[kInstTessOutInvocationId] << ". ";
+        } break;
+        case 3: {
+            strm << "Stage = Geometry.  Primitive ID = " << debug_record[kInstGeomOutPrimitiveId]
+                 << " Invocation ID = " << debug_record[kInstGeomOutInvocationId] << ". ";
+        } break;
+        case 4: {
+            strm << "Stage = Fragment.  Fragment coord (x,y) = ("
+                 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordX]) << ", "
+                 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordY]) << "). ";
+        } break;
+        case 5: {
+            strm << "Stage = Compute.  Global invocation ID = " << debug_record[kInstCompOutGlobalInvocationId] << ". ";
+        } break;
+        default: {
+            strm << "Internal Error (unexpected stage = " << debug_record[kInstCommonOutStageIdx] << "). ";
+            assert(false);
+        } break;
+    }
+    msg = strm.str();
+}
+
+// Generate the part of the message describing the violation.
+static void GenerateValidationMessage(const uint32_t *debug_record, std::string &msg, std::string &vuid_msg) {
+    using namespace spvtools;
+    std::ostringstream strm;
+    switch (debug_record[kInstValidationOutError]) {
+        case 0: {
+            strm << "Index of " << debug_record[kInstBindlessOutDescIndex] << " used to index descriptor array of length "
+                 << debug_record[kInstBindlessOutDescBound] << ". ";
+            vuid_msg = "UNASSIGNED-Descriptor index out of bounds";
+        } break;
+        case 1: {
+            strm << "Descriptor index " << debug_record[kInstBindlessOutDescIndex] << " is uninitialized. ";
+            vuid_msg = "UNASSIGNED-Descriptor uninitialized";
+        } break;
+        default: {
+            strm << "Internal Error (unexpected error type = " << debug_record[kInstValidationOutError] << "). ";
+            vuid_msg = "UNASSIGNED-Internal Error";
+            assert(false);
+        } break;
+    }
+    msg = strm.str();
+}
+
+static std::string LookupDebugUtilsName(const debug_report_data *report_data, const uint64_t object) {
+    auto object_label = report_data->DebugReportGetUtilsObjectName(object);
+    if (object_label != "") {
+        object_label = "(" + object_label + ")";
+    }
+    return object_label;
+}
+
+// Generate message from the common portion of the debug report record.
+static void GenerateCommonMessage(const debug_report_data *report_data, const GLOBAL_CB_NODE *cb_node, const uint32_t *debug_record,
+                                  const VkShaderModule shader_module_handle, const VkPipeline pipeline_handle,
+                                  const uint32_t draw_index, std::string &msg) {
+    using namespace spvtools;
+    std::ostringstream strm;
+    if (shader_module_handle == VK_NULL_HANDLE) {
+        strm << std::hex << std::showbase << "Internal Error: Unable to locate information for shader used in command buffer "
+             << LookupDebugUtilsName(report_data, HandleToUint64(cb_node->commandBuffer)) << "("
+             << HandleToUint64(cb_node->commandBuffer) << "). ";
+        assert(true);
+    } else {
+        strm << std::hex << std::showbase << "Command buffer "
+             << LookupDebugUtilsName(report_data, HandleToUint64(cb_node->commandBuffer)) << "("
+             << HandleToUint64(cb_node->commandBuffer) << "). "
+             << "Draw Index " << draw_index << ". "
+             << "Pipeline " << LookupDebugUtilsName(report_data, HandleToUint64(pipeline_handle)) << "("
+             << HandleToUint64(pipeline_handle) << "). "
+             << "Shader Module " << LookupDebugUtilsName(report_data, HandleToUint64(shader_module_handle)) << "("
+             << HandleToUint64(shader_module_handle) << "). ";
+    }
+    strm << std::dec << std::noshowbase;
+    strm << "Shader Instruction Index = " << debug_record[kInstCommonOutInstructionIdx] << ". ";
+    msg = strm.str();
+}
+
+// Read the contents of the SPIR-V OpSource instruction and any following continuation instructions.
+// Split the single string into a vector of strings, one for each line, for easier processing.
+static void ReadOpSource(const shader_module &shader, const uint32_t reported_file_id, std::vector<std::string> &opsource_lines) {
+    for (auto insn : shader) {
+        if ((insn.opcode() == spv::OpSource) && (insn.len() >= 5) && (insn.word(3) == reported_file_id)) {
+            std::istringstream in_stream;
+            std::string cur_line;
+            in_stream.str((char *)&insn.word(4));
+            while (std::getline(in_stream, cur_line)) {
+                opsource_lines.push_back(cur_line);
+            }
+            while ((++insn).opcode() == spv::OpSourceContinued) {
+                in_stream.str((char *)&insn.word(1));
+                while (std::getline(in_stream, cur_line)) {
+                    opsource_lines.push_back(cur_line);
+                }
+            }
+            break;
+        }
+    }
+}
+
+// The task here is to search the OpSource content to find the #line directive with the
+// line number that is closest to, but still prior to the reported error line number and
+// still within the reported filename.
+// From this known position in the OpSource content we can add the difference between
+// the #line line number and the reported error line number to determine the location
+// in the OpSource content of the reported error line.
+//
+// Considerations:
+// - Look only at #line directives that specify the reported_filename since
+//   the reported error line number refers to its location in the reported filename.
+// - If a #line directive does not have a filename, the file is the reported filename, or
+//   the filename found in a prior #line directive.  (This is C-preprocessor behavior)
+// - It is possible (e.g., inlining) for blocks of code to get shuffled out of their
+//   original order and the #line directives are used to keep the numbering correct.  This
+//   is why we need to examine the entire contents of the source, instead of leaving early
+//   when finding a #line line number larger than the reported error line number.
+//
+
+// GCC 4.8 has a problem with std::regex that is fixed in GCC 4.9.  Provide fallback code for 4.8
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+
+#if defined(__GNUC__) && GCC_VERSION < 40900
+static bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
+    // # line <linenumber> "<filename>" or
+    // #line <linenumber> "<filename>"
+    std::vector<std::string> tokens;
+    std::stringstream stream(string);
+    std::string temp;
+    uint32_t line_index = 0;
+
+    while (stream >> temp) tokens.push_back(temp);
+    auto size = tokens.size();
+    if (size > 1) {
+        if (tokens[0] == "#" && tokens[1] == "line") {
+            line_index = 2;
+        } else if (tokens[0] == "#line") {
+            line_index = 1;
+        }
+    }
+    if (0 == line_index) return false;
+    *linenumber = std::stoul(tokens[line_index]);
+    uint32_t filename_index = line_index + 1;
+    // Remove enclosing double quotes around filename
+    if (size > filename_index) filename = tokens[filename_index].substr(1, tokens[filename_index].size() - 2);
+    return true;
+}
+#else
+static bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
+    static const std::regex line_regex(  // matches #line directives
+        "^"                              // beginning of line
+        "\\s*"                           // optional whitespace
+        "#"                              // required text
+        "\\s*"                           // optional whitespace
+        "line"                           // required text
+        "\\s+"                           // required whitespace
+        "([0-9]+)"                       // required first capture - line number
+        "(\\s+)?"                        // optional second capture - whitespace
+        "(\".+\")?"                      // optional third capture - quoted filename with at least one char inside
+        ".*");                           // rest of line (needed when using std::regex_match since the entire line is tested)
+
+    std::smatch captures;
+
+    bool found_line = std::regex_match(string, captures, line_regex);
+    if (!found_line) return false;
+
+    // filename is optional and considered found only if the whitespace and the filename are captured
+    if (captures[2].matched && captures[3].matched) {
+        // Remove enclosing double quotes.  The regex guarantees the quotes and at least one char.
+        filename = captures[3].str().substr(1, captures[3].str().size() - 2);
+    }
+    *linenumber = std::stoul(captures[1]);
+    return true;
+}
+#endif  // GCC_VERSION
+
+// Extract the filename, line number, and column number from the correct OpLine and build a message string from it.
+// Scan the source (from OpSource) to find the line of source at the reported line number and place it in another message string.
+static void GenerateSourceMessages(const std::vector<unsigned int> &pgm, const uint32_t *debug_record, std::string &filename_msg,
+                                   std::string &source_msg) {
+    using namespace spvtools;
+    std::ostringstream filename_stream;
+    std::ostringstream source_stream;
+    shader_module shader;
+    shader.words = pgm;
+    // Find the OpLine just before the failing instruction indicated by the debug info.
+    // SPIR-V can only be iterated in the forward direction due to its opcode/length encoding.
+    uint32_t instruction_index = 0;
+    uint32_t reported_file_id = 0;
+    uint32_t reported_line_number = 0;
+    uint32_t reported_column_number = 0;
+    if (shader.words.size() > 0) {
+        for (auto insn : shader) {
+            if (insn.opcode() == spv::OpLine) {
+                reported_file_id = insn.word(1);
+                reported_line_number = insn.word(2);
+                reported_column_number = insn.word(3);
+            }
+            if (instruction_index == debug_record[kInstCommonOutInstructionIdx]) {
+                break;
+            }
+            instruction_index++;
+        }
+    }
+    // Create message with file information obtained from the OpString pointed to by the discovered OpLine.
+    std::string reported_filename;
+    if (reported_file_id == 0) {
+        filename_stream
+            << "Unable to find SPIR-V OpLine for source information.  Build shader with debug info to get source information.";
+    } else {
+        bool found_opstring = false;
+        for (auto insn : shader) {
+            if ((insn.opcode() == spv::OpString) && (insn.len() >= 3) && (insn.word(1) == reported_file_id)) {
+                found_opstring = true;
+                reported_filename = (char *)&insn.word(2);
+                if (reported_filename.empty()) {
+                    filename_stream << "Shader validation error occurred at line " << reported_line_number;
+                } else {
+                    filename_stream << "Shader validation error occurred in file: " << reported_filename << " at line "
+                                    << reported_line_number;
+                }
+                if (reported_column_number > 0) {
+                    filename_stream << ", column " << reported_column_number;
+                }
+                filename_stream << ".";
+                break;
+            }
+        }
+        if (!found_opstring) {
+            filename_stream << "Unable to find SPIR-V OpString for file id " << reported_file_id << " from OpLine instruction.";
+        }
+    }
+    filename_msg = filename_stream.str();
+
+    // Create message to display source code line containing error.
+    if ((reported_file_id != 0)) {
+        // Read the source code and split it up into separate lines.
+        std::vector<std::string> opsource_lines;
+        ReadOpSource(shader, reported_file_id, opsource_lines);
+        // Find the line in the OpSource content that corresponds to the reported error file and line.
+        if (!opsource_lines.empty()) {
+            uint32_t saved_line_number = 0;
+            std::string current_filename = reported_filename;  // current "preprocessor" filename state.
+            std::vector<std::string>::size_type saved_opsource_offset = 0;
+            bool found_best_line = false;
+            for (auto it = opsource_lines.begin(); it != opsource_lines.end(); ++it) {
+                uint32_t parsed_line_number;
+                std::string parsed_filename;
+                bool found_line = GetLineAndFilename(*it, &parsed_line_number, parsed_filename);
+                if (!found_line) continue;
+
+                bool found_filename = parsed_filename.size() > 0;
+                if (found_filename) {
+                    current_filename = parsed_filename;
+                }
+                if ((!found_filename) || (current_filename == reported_filename)) {
+                    // Update the candidate best line directive, if the current one is prior and closer to the reported line
+                    if (reported_line_number >= parsed_line_number) {
+                        if (!found_best_line ||
+                            (reported_line_number - parsed_line_number <= reported_line_number - saved_line_number)) {
+                            saved_line_number = parsed_line_number;
+                            saved_opsource_offset = std::distance(opsource_lines.begin(), it);
+                            found_best_line = true;
+                        }
+                    }
+                }
+            }
+            if (found_best_line) {
+                assert(reported_line_number >= saved_line_number);
+                std::vector<std::string>::size_type opsource_index =
+                    (reported_line_number - saved_line_number) + 1 + saved_opsource_offset;
+                if (opsource_index < opsource_lines.size()) {
+                    source_stream << "\n" << reported_line_number << ": " << opsource_lines[opsource_index].c_str();
+                } else {
+                    source_stream << "Internal error: calculated source line of " << opsource_index << " for source size of "
+                                  << opsource_lines.size() << " lines.";
+                }
+            } else {
+                source_stream << "Unable to find suitable #line directive in SPIR-V OpSource.";
+            }
+        } else {
+            source_stream << "Unable to find SPIR-V OpSource.";
+        }
+    }
+    source_msg = source_stream.str();
+}
+
+// Pull together all the information from the debug record to build the error message strings,
+// and then assemble them into a single message string.
+// Retrieve the shader program referenced by the unique shader ID provided in the debug record.
+// We had to keep a copy of the shader program with the same lifecycle as the pipeline to make
+// sure it is available when the pipeline is submitted.  (The ShaderModule tracking object also
+// keeps a copy, but it can be destroyed after the pipeline is created and before it is submitted.)
+//
+void CoreChecks::AnalyzeAndReportError(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkQueue queue, uint32_t draw_index,
+                                       uint32_t *const debug_output_buffer) {
+    using namespace spvtools;
+    const uint32_t total_words = debug_output_buffer[0];
+    // A zero here means that the shader instrumentation didn't write anything.
+    // If you have nothing to say, don't say it here.
+    if (0 == total_words) {
+        return;
+    }
+    // The first word in the debug output buffer is the number of words that would have
+    // been written by the shader instrumentation, if there was enough room in the buffer we provided.
+    // The number of words actually written by the shaders is determined by the size of the buffer
+    // we provide via the descriptor.  So, we process only the number of words that can fit in the
+    // buffer.
+    // Each "report" written by the shader instrumentation is considered a "record".  This function
+    // is hard-coded to process only one record because it expects the buffer to be large enough to
+    // hold only one record.  If there is a desire to process more than one record, this function needs
+    // to be modified to loop over records and the buffer size increased.
+    auto gpu_state = GetGpuValidationState();
+    std::string validation_message;
+    std::string stage_message;
+    std::string common_message;
+    std::string filename_message;
+    std::string source_message;
+    std::string vuid_msg;
+    VkShaderModule shader_module_handle = VK_NULL_HANDLE;
+    VkPipeline pipeline_handle = VK_NULL_HANDLE;
+    std::vector<unsigned int> pgm;
+    // The first record starts at this offset after the total_words.
+    const uint32_t *debug_record = &debug_output_buffer[kDebugOutputDataOffset];
+    // Lookup the VkShaderModule handle and SPIR-V code used to create the shader, using the unique shader ID value returned
+    // by the instrumented shader.
+    auto it = gpu_state->shader_map.find(debug_record[kInstCommonOutShaderId]);
+    if (it != gpu_state->shader_map.end()) {
+        shader_module_handle = it->second.shader_module;
+        pipeline_handle = it->second.pipeline;
+        pgm = it->second.pgm;
+    }
+    GenerateValidationMessage(debug_record, validation_message, vuid_msg);
+    GenerateStageMessage(debug_record, stage_message);
+    GenerateCommonMessage(report_data, cb_node, debug_record, shader_module_handle, pipeline_handle, draw_index, common_message);
+    GenerateSourceMessages(pgm, debug_record, filename_message, source_message);
+    log_msg(GetReportData(), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, HandleToUint64(queue),
+            vuid_msg.c_str(), "%s %s %s %s%s", validation_message.c_str(), common_message.c_str(), stage_message.c_str(),
+            filename_message.c_str(), source_message.c_str());
+    // The debug record at word kInstCommonOutSize is the number of words in the record
+    // written by the shader.  Clear the entire record plus the total_words word at the start.
+    const uint32_t words_to_clear = 1 + std::min(debug_record[kInstCommonOutSize], (uint32_t)kInstMaxOutCnt);
+    memset(debug_output_buffer, 0, sizeof(uint32_t) * words_to_clear);
+}
+
+// For the given command buffer, map its debug data buffers and read their contents for analysis.
+void CoreChecks::ProcessInstrumentationBuffer(const layer_data *dev_data, VkQueue queue, GLOBAL_CB_NODE *cb_node) {
+    auto gpu_state = GetGpuValidationState();
+    if (cb_node && cb_node->hasDrawCmd && cb_node->gpu_buffer_list.size() > 0) {
+        VkResult result;
+        char *pData;
+        uint32_t draw_index = 0;
+        for (auto &buffer_info : cb_node->gpu_buffer_list) {
+            uint32_t block_offset = buffer_info.mem_block.offset;
+            uint32_t block_size = gpu_state->memory_manager->GetBlockSize();
+            uint32_t offset_to_data = 0;
+            const uint32_t map_align = std::max(1U, static_cast<uint32_t>(GetPDProperties()->limits.minMemoryMapAlignment));
+
+            // Adjust the offset to the alignment required for mapping.
+            block_offset = (block_offset / map_align) * map_align;
+            offset_to_data = buffer_info.mem_block.offset - block_offset;
+            block_size += offset_to_data;
+            result = GetDispatchTable()->MapMemory(cb_node->device, buffer_info.mem_block.memory, block_offset, block_size, 0,
+                                                   (void **)&pData);
+            // Analyze debug output buffer
+            if (result == VK_SUCCESS) {
+                AnalyzeAndReportError(dev_data, cb_node, queue, draw_index, (uint32_t *)(pData + offset_to_data));
+                GetDispatchTable()->UnmapMemory(cb_node->device, buffer_info.mem_block.memory);
+            }
+            draw_index++;
+        }
+    }
+}
+
+// Submit a memory barrier on graphics queues.
+// Lazy-create and record the needed command buffer.
+void CoreChecks::SubmitBarrier(layer_data *dev_data, VkQueue queue) {
+    auto gpu_state = GetGpuValidationState();
+    const auto *dispatch_table = GetDispatchTable();
+    uint32_t queue_family_index = 0;
+
+    auto it = dev_data->queueMap.find(queue);
+    if (it != dev_data->queueMap.end()) {
+        queue_family_index = it->second.queueFamilyIndex;
+    }
+
+    // Pay attention only to queues that support graphics.
+    // This ensures that the command buffer pool is created so that it can be used on a graphics queue.
+    VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[queue_family_index].queueFlags;
+    if (!(queue_flags & VK_QUEUE_GRAPHICS_BIT)) {
+        return;
+    }
+
+    // Lazy-allocate and record the command buffer.
+    if (gpu_state->barrier_command_buffer == VK_NULL_HANDLE) {
+        VkResult result;
+        VkCommandPoolCreateInfo pool_create_info = {};
+        pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+        pool_create_info.queueFamilyIndex = queue_family_index;
+        result = dispatch_table->CreateCommandPool(GetDevice(), &pool_create_info, nullptr, &gpu_state->barrier_command_pool);
+        if (result != VK_SUCCESS) {
+            ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                               "Unable to create command pool for barrier CB.");
+            gpu_state->barrier_command_pool = VK_NULL_HANDLE;
+            return;
+        }
+
+        VkCommandBufferAllocateInfo command_buffer_alloc_info = {};
+        command_buffer_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+        command_buffer_alloc_info.commandPool = gpu_state->barrier_command_pool;
+        command_buffer_alloc_info.commandBufferCount = 1;
+        command_buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+        result =
+            dispatch_table->AllocateCommandBuffers(GetDevice(), &command_buffer_alloc_info, &gpu_state->barrier_command_buffer);
+        if (result != VK_SUCCESS) {
+            ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                               "Unable to create barrier command buffer.");
+            dispatch_table->DestroyCommandPool(GetDevice(), gpu_state->barrier_command_pool, nullptr);
+            gpu_state->barrier_command_pool = VK_NULL_HANDLE;
+            gpu_state->barrier_command_buffer = VK_NULL_HANDLE;
+            return;
+        }
+
+        // Hook up command buffer dispatch
+        *((const void **)gpu_state->barrier_command_buffer) = *(void **)(GetDevice());
+
+        // Record a global memory barrier to force availability of device memory operations to the host domain.
+        VkCommandBufferBeginInfo command_buffer_begin_info = {};
+        command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+        result = dispatch_table->BeginCommandBuffer(gpu_state->barrier_command_buffer, &command_buffer_begin_info);
+
+        if (result == VK_SUCCESS) {
+            VkMemoryBarrier memory_barrier = {};
+            memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+            memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
+            memory_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
+
+            dispatch_table->CmdPipelineBarrier(gpu_state->barrier_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                                               VK_PIPELINE_STAGE_HOST_BIT, 0, 1, &memory_barrier, 0, nullptr, 0, nullptr);
+            dispatch_table->EndCommandBuffer(gpu_state->barrier_command_buffer);
+        }
+    }
+
+    if (gpu_state->barrier_command_buffer) {
+        VkSubmitInfo submit_info = {};
+        submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+        submit_info.commandBufferCount = 1;
+        submit_info.pCommandBuffers = &gpu_state->barrier_command_buffer;
+        dispatch_table->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
+    }
+}
+
+// Issue a memory barrier to make GPU-written data available to host.
+// Wait for the queue to complete execution.
+// Check the debug buffers for all the command buffers that were submitted.
+void CoreChecks::GpuPostCallQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
+                                        VkFence fence) {
+    auto gpu_state = GetGpuValidationState();
+    if (gpu_state->aborted) return;
+
+    SubmitBarrier(dev_data, queue);
+
+    dev_data->device_dispatch_table.QueueWaitIdle(queue);
+
+    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
+        const VkSubmitInfo *submit = &pSubmits[submit_idx];
+        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
+            auto cb_node = GetCBNode(submit->pCommandBuffers[i]);
+            ProcessInstrumentationBuffer(dev_data, queue, cb_node);
+            for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
+                ProcessInstrumentationBuffer(dev_data, queue, secondaryCmdBuffer);
+            }
+        }
+    }
+}
+
+void CoreChecks::GpuAllocateValidationResources(layer_data *dev_data, const VkCommandBuffer cmd_buffer,
+                                                const VkPipelineBindPoint bind_point) {
+    VkResult result;
+
+    if (!(GetEnables()->gpu_validation)) return;
+
+    auto gpu_state = GetGpuValidationState();
+    if (gpu_state->aborted) return;
+
+    std::vector<VkDescriptorSet> desc_sets;
+    VkDescriptorPool desc_pool = VK_NULL_HANDLE;
+    result = gpu_state->desc_set_manager->GetDescriptorSets(1, &desc_pool, &desc_sets);
+    assert(result == VK_SUCCESS);
+    if (result != VK_SUCCESS) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unable to allocate descriptor sets.  Device could become unstable.");
+        gpu_state->aborted = true;
+        return;
+    }
+
+    VkDescriptorBufferInfo desc_buffer_info = {};
+    desc_buffer_info.range = gpu_state->memory_manager->GetBlockSize();
+
+    auto cb_node = GetCBNode(cmd_buffer);
+    if (!cb_node) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unrecognized command buffer");
+        gpu_state->aborted = true;
+        return;
+    }
+
+    GpuDeviceMemoryBlock block = {};
+    result = gpu_state->memory_manager->GetBlock(&block);
+    if (result != VK_SUCCESS) {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unable to allocate device memory.  Device could become unstable.");
+        gpu_state->aborted = true;
+        return;
+    }
+
+    // Record buffer and memory info in CB state tracking
+    cb_node->gpu_buffer_list.emplace_back(block, desc_sets[0], desc_pool);
+
+    // Write the descriptor
+    desc_buffer_info.buffer = block.buffer;
+    desc_buffer_info.offset = block.offset;
+
+    VkWriteDescriptorSet desc_write = {};
+    desc_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    desc_write.descriptorCount = 1;
+    desc_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+    desc_write.pBufferInfo = &desc_buffer_info;
+    desc_write.dstSet = desc_sets[0];
+    GetDispatchTable()->UpdateDescriptorSets(GetDevice(), 1, &desc_write, 0, NULL);
+
+    auto iter = cb_node->lastBound.find(VK_PIPELINE_BIND_POINT_GRAPHICS);  // find() allows read-only access to cb_state
+    if (iter != cb_node->lastBound.end()) {
+        auto pipeline_state = iter->second.pipeline_state;
+        if (pipeline_state && (pipeline_state->pipeline_layout.set_layouts.size() <= gpu_state->desc_set_bind_index)) {
+            GetDispatchTable()->CmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                                      pipeline_state->pipeline_layout.layout, gpu_state->desc_set_bind_index, 1,
+                                                      desc_sets.data(), 0, nullptr);
+        }
+    } else {
+        ReportSetupProblem(dev_data, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, HandleToUint64(GetDevice()),
+                           "Unable to find pipeline state");
+        gpu_state->aborted = true;
+        return;
+    }
+}
diff --git a/layers/gpu_validation.h b/layers/gpu_validation.h
new file mode 100644
index 0000000..ea17c3a
--- /dev/null
+++ b/layers/gpu_validation.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2018-2019 The Khronos Group Inc.
+ * Copyright (c) 2018-2019 Valve Corporation
+ * Copyright (c) 2018-2019 LunarG, Inc.
+ * Copyright (C) 2018-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef VULKAN_GPU_VALIDATION_H
+#define VULKAN_GPU_VALIDATION_H
+
+// Class to encapsulate Vulkan Device Memory allocations.
+// It allocates device memory in large chunks for efficiency and to avoid
+// hitting the device limit of the number of allocations.
+// This manager handles only fixed-sized blocks of "data_size" bytes.
+// The interface allows the caller to "get" and "put back" blocks.
+// The manager allocates and frees chunks as needed.
+
+class CoreChecks;
+typedef CoreChecks layer_data;
+
+class GpuDeviceMemoryManager {
+   public:
+    GpuDeviceMemoryManager(layer_data *dev_data, uint32_t data_size);
+    ~GpuDeviceMemoryManager();
+
+    uint32_t GetBlockSize() { return block_size_; }
+
+    VkResult GetBlock(GpuDeviceMemoryBlock *block);
+    void PutBackBlock(VkBuffer buffer, VkDeviceMemory memory, uint32_t offset);
+    void PutBackBlock(GpuDeviceMemoryBlock &block);
+    void FreeAllBlocks();
+
+   private:
+    // Define allocation granularity of Vulkan resources.
+    // Things like device memory and descriptors are allocated in "chunks".
+    // This number should be chosen to try to avoid too many chunk allocations
+    // and chunk allocations that are too large.
+    static const uint32_t kItemsPerChunk = 512;
+
+    struct MemoryChunk {
+        VkBuffer buffer;
+        VkDeviceMemory memory;
+        std::vector<uint32_t> available_offsets;
+    };
+
+    layer_data *dev_data_;
+    uint32_t record_size_;
+    uint32_t block_size_;
+    uint32_t blocks_per_chunk_;
+    uint32_t chunk_size_;
+    std::list<MemoryChunk> chunk_list_;
+
+    bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
+    VkResult AllocMemoryChunk(MemoryChunk &chunk);
+    void FreeMemoryChunk(MemoryChunk &chunk);
+};
+
+// Class to encapsulate Descriptor Set allocation.  This manager creates and destroys Descriptor Pools
+// as needed to satisfy requests for descriptor sets.
+class GpuDescriptorSetManager {
+   public:
+    GpuDescriptorSetManager(layer_data *dev_data);
+    ~GpuDescriptorSetManager();
+
+    VkResult GetDescriptorSets(uint32_t count, VkDescriptorPool *pool, std::vector<VkDescriptorSet> *desc_sets);
+    void PutBackDescriptorSet(VkDescriptorPool desc_pool, VkDescriptorSet desc_set);
+    void DestroyDescriptorPools();
+
+   private:
+    static const uint32_t kItemsPerChunk = 512;
+    struct PoolTracker {
+        uint32_t size;
+        uint32_t used;
+    };
+
+    layer_data *dev_data_;
+    std::unordered_map<VkDescriptorPool, struct PoolTracker> desc_pool_map_;
+};
+
+using mutex_t = std::mutex;
+using lock_guard_t = std::lock_guard<mutex_t>;
+using unique_lock_t = std::unique_lock<mutex_t>;
+
+#endif  // VULKAN_GPU_VALIDATION_H
diff --git a/layers/hash_vk_types.h b/layers/hash_vk_types.h
index b1b99b4..6985886 100644
--- a/layers/hash_vk_types.h
+++ b/layers/hash_vk_types.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2018 The Khronos Group Inc.
- * Copyright (c) 2018 Valve Corporation
- * Copyright (c) 2018 LunarG, Inc.
+/* Copyright (c) 2019 The Khronos Group Inc.
+ * Copyright (c) 2019 Valve Corporation
+ * Copyright (c) 2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,7 +62,7 @@
 }  // namespace std
 
 // VkPushConstantRange
-static bool operator==(const VkPushConstantRange &lhs, const VkPushConstantRange &rhs) {
+static inline bool operator==(const VkPushConstantRange &lhs, const VkPushConstantRange &rhs) {
     return (lhs.stageFlags == rhs.stageFlags) && (lhs.offset == rhs.offset) && (lhs.size == rhs.size);
 }
 
diff --git a/layers/json/VkLayer_object_tracker.json.in b/layers/json/VkLayer_object_lifetimes.json.in
similarity index 100%
rename from layers/json/VkLayer_object_tracker.json.in
rename to layers/json/VkLayer_object_lifetimes.json.in
diff --git a/layers/json/VkLayer_parameter_validation.json.in b/layers/json/VkLayer_stateless_validation.json.in
similarity index 100%
rename from layers/json/VkLayer_parameter_validation.json.in
rename to layers/json/VkLayer_stateless_validation.json.in
diff --git a/layers/json/VkLayer_threading.json.in b/layers/json/VkLayer_thread_safety.json.in
similarity index 100%
rename from layers/json/VkLayer_threading.json.in
rename to layers/json/VkLayer_thread_safety.json.in
diff --git a/layers/object_lifetime_validation.h b/layers/object_lifetime_validation.h
new file mode 100644
index 0000000..cdf5ee0
--- /dev/null
+++ b/layers/object_lifetime_validation.h
@@ -0,0 +1,265 @@
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ * Author: Jon Ashburn <jon@lunarg.com>
+ * Author: Tobin Ehlis <tobine@google.com>
+ */
+
+// Suppress unused warning on Linux
+#if defined(__GNUC__)
+#define DECORATE_UNUSED __attribute__((unused))
+#else
+#define DECORATE_UNUSED
+#endif
+
+// clang-format off
+static const char DECORATE_UNUSED *kVUID_ObjectTracker_Info = "UNASSIGNED-ObjectTracker-Info";
+static const char DECORATE_UNUSED *kVUID_ObjectTracker_InternalError = "UNASSIGNED-ObjectTracker-InternalError";
+static const char DECORATE_UNUSED *kVUID_ObjectTracker_ObjectLeak =    "UNASSIGNED-ObjectTracker-ObjectLeak";
+static const char DECORATE_UNUSED *kVUID_ObjectTracker_UnknownObject = "UNASSIGNED-ObjectTracker-UnknownObject";
+// clang-format on
+
+#undef DECORATE_UNUSED
+
+extern uint64_t object_track_index;
+
+// Object Status -- used to track state of individual objects
+typedef VkFlags ObjectStatusFlags;
+enum ObjectStatusFlagBits {
+    OBJSTATUS_NONE = 0x00000000,                      // No status is set
+    OBJSTATUS_FENCE_IS_SUBMITTED = 0x00000001,        // Fence has been submitted
+    OBJSTATUS_VIEWPORT_BOUND = 0x00000002,            // Viewport state object has been bound
+    OBJSTATUS_RASTER_BOUND = 0x00000004,              // Viewport state object has been bound
+    OBJSTATUS_COLOR_BLEND_BOUND = 0x00000008,         // Viewport state object has been bound
+    OBJSTATUS_DEPTH_STENCIL_BOUND = 0x00000010,       // Viewport state object has been bound
+    OBJSTATUS_GPU_MEM_MAPPED = 0x00000020,            // Memory object is currently mapped
+    OBJSTATUS_COMMAND_BUFFER_SECONDARY = 0x00000040,  // Command Buffer is of type SECONDARY
+    OBJSTATUS_CUSTOM_ALLOCATOR = 0x00000080,          // Allocated with custom allocator
+};
+
+// Object and state information structure
+struct ObjTrackState {
+    uint64_t handle;                                               // Object handle (new)
+    VulkanObjectType object_type;                                  // Object type identifier
+    ObjectStatusFlags status;                                      // Object state
+    uint64_t parent_object;                                        // Parent object
+    std::unique_ptr<std::unordered_set<uint64_t> > child_objects;  // Child objects (used for VkDescriptorPool only)
+};
+
+// Track Queue information
+struct ObjTrackQueueInfo {
+    uint32_t queue_node_index;
+    VkQueue queue;
+};
+
+typedef std::unordered_map<uint64_t, ObjTrackState *> object_map_type;
+
+class ObjectLifetimes : public ValidationObject {
+   public:
+    uint64_t num_objects[kVulkanObjectTypeMax + 1];
+    uint64_t num_total_objects;
+    // Vector of unordered_maps per object type to hold ObjTrackState info
+    std::vector<object_map_type> object_map;
+    // Special-case map for swapchain images
+    std::unordered_map<uint64_t, ObjTrackState *> swapchainImageMap;
+    // Map of queue information structures, one per queue
+    std::unordered_map<VkQueue, ObjTrackQueueInfo *> queue_info_map;
+
+    std::vector<VkQueueFamilyProperties> queue_family_properties;
+
+    // Constructor for object lifetime tracking
+    ObjectLifetimes() : num_objects{}, num_total_objects(0), object_map{} { object_map.resize(kVulkanObjectTypeMax + 1); }
+
+    bool DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, const std::string &error_code);
+    void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type);
+    void CreateQueue(VkDevice device, VkQueue vkObj);
+    void AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue);
+    void ValidateQueueFlags(VkQueue queue, const char *function);
+    void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer,
+                               VkCommandBufferLevel level);
+    void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set);
+    void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain);
+    bool ReportUndestroyedObjects(VkDevice device, const std::string &error_code);
+    void DestroyUndestroyedObjects(VkDevice device);
+    bool ValidateDeviceObject(uint64_t device_handle, const char *invalid_handle_code, const char *wrong_device_code);
+    void DestroyQueueDataStructures(VkDevice device);
+    bool ValidateCommandBuffer(VkDevice device, VkCommandPool command_pool, VkCommandBuffer command_buffer);
+    bool ValidateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set);
+    bool ValidateSamplerObjects(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo);
+    template <typename DispObj>
+    bool ValidateDescriptorWrite(DispObj disp, VkWriteDescriptorSet const *desc, bool isPush);
+
+    ObjectLifetimes *GetObjectLifetimeData(std::vector<ValidationObject *> &object_dispatch) {
+        for (auto layer_object : object_dispatch) {
+            if (layer_object->container_type == LayerObjectTypeObjectTracker) {
+                return (reinterpret_cast<ObjectLifetimes *>(layer_object));
+            }
+        }
+        return nullptr;
+    };
+
+    template <typename T1, typename T2>
+    bool ValidateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, bool null_allowed,
+                        const char *invalid_handle_code, const char *wrong_device_code) {
+        if (null_allowed && (object == VK_NULL_HANDLE)) {
+            return false;
+        }
+        auto object_handle = HandleToUint64(object);
+
+        if (object_type == kVulkanObjectTypeDevice) {
+            return ValidateDeviceObject(object_handle, invalid_handle_code, wrong_device_code);
+        }
+
+        VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
+
+        // Look for object in object map
+        if (object_map[object_type].find(object_handle) == object_map[object_type].end()) {
+            // If object is an image, also look for it in the swapchain image map
+            if ((object_type != kVulkanObjectTypeImage) || (swapchainImageMap.find(object_handle) == swapchainImageMap.end())) {
+                // Object not found, look for it in other device object maps
+                for (auto other_device_data : layer_data_map) {
+                    for (auto layer_object_data : other_device_data.second->object_dispatch) {
+                        if (layer_object_data->container_type == LayerObjectTypeObjectTracker) {
+                            auto object_lifetime_data = reinterpret_cast<ObjectLifetimes *>(layer_object_data);
+                            if (object_lifetime_data && (object_lifetime_data != this)) {
+                                if (object_lifetime_data->object_map[object_type].find(object_handle) !=
+                                        object_lifetime_data->object_map[object_type].end() ||
+                                    (object_type == kVulkanObjectTypeImage &&
+                                     object_lifetime_data->swapchainImageMap.find(object_handle) !=
+                                         object_lifetime_data->swapchainImageMap.end())) {
+                                    // Object found on other device, report an error if object has a device parent error code
+                                    if ((wrong_device_code != kVUIDUndefined) && (object_type != kVulkanObjectTypeSurfaceKHR)) {
+                                        return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
+                                                       wrong_device_code,
+                                                       "Object 0x%" PRIxLEAST64
+                                                       " was not created, allocated or retrieved from the correct device.",
+                                                       object_handle);
+                                    } else {
+                                        return false;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                // Report an error if object was not found anywhere
+                return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle, invalid_handle_code,
+                               "Invalid %s Object 0x%" PRIxLEAST64 ".", object_string[object_type], object_handle);
+            }
+        }
+        return false;
+    }
+
+    template <typename T1, typename T2>
+    void CreateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator) {
+        uint64_t object_handle = HandleToUint64(object);
+        bool custom_allocator = (pAllocator != nullptr);
+        if (!object_map[object_type].count(object_handle)) {
+            VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
+            log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle, kVUID_ObjectTracker_Info,
+                    "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++, object_string[object_type],
+                    object_handle);
+
+            ObjTrackState *pNewObjNode = new ObjTrackState;
+            pNewObjNode->object_type = object_type;
+            pNewObjNode->status = custom_allocator ? OBJSTATUS_CUSTOM_ALLOCATOR : OBJSTATUS_NONE;
+            pNewObjNode->handle = object_handle;
+
+            object_map[object_type][object_handle] = pNewObjNode;
+            num_objects[object_type]++;
+            num_total_objects++;
+
+            if (object_type == kVulkanObjectTypeDescriptorPool) {
+                pNewObjNode->child_objects.reset(new std::unordered_set<uint64_t>);
+            }
+        }
+    }
+
+    template <typename T1>
+    void DestroyObjectSilently(T1 object, VulkanObjectType object_type) {
+        auto object_handle = HandleToUint64(object);
+        assert(object_handle != VK_NULL_HANDLE);
+
+        auto item = object_map[object_type].find(object_handle);
+        assert(item != object_map[object_type].end());
+
+        ObjTrackState *pNode = item->second;
+        assert(num_total_objects > 0);
+
+        num_total_objects--;
+        assert(num_objects[pNode->object_type] > 0);
+
+        num_objects[pNode->object_type]--;
+
+        delete pNode;
+        object_map[object_type].erase(item);
+    }
+
+    template <typename T1, typename T2>
+    void RecordDestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type) {
+        auto object_handle = HandleToUint64(object);
+        if (object_handle != VK_NULL_HANDLE) {
+            auto item = object_map[object_type].find(object_handle);
+            if (item != object_map[object_type].end()) {
+                DestroyObjectSilently(object, object_type);
+            }
+        }
+    }
+
+    template <typename T1, typename T2>
+    bool ValidateDestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type,
+                               const VkAllocationCallbacks *pAllocator, const char *expected_custom_allocator_code,
+                               const char *expected_default_allocator_code) {
+        auto object_handle = HandleToUint64(object);
+        bool custom_allocator = pAllocator != nullptr;
+        VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
+        bool skip = false;
+
+        if (object_handle != VK_NULL_HANDLE) {
+            auto item = object_map[object_type].find(object_handle);
+            if (item != object_map[object_type].end()) {
+                ObjTrackState *pNode = item->second;
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle,
+                                kVUID_ObjectTracker_Info,
+                                "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
+                                object_string[object_type], HandleToUint64(object), num_total_objects - 1,
+                                num_objects[pNode->object_type] - 1, object_string[object_type]);
+
+                auto allocated_with_custom = (pNode->status & OBJSTATUS_CUSTOM_ALLOCATOR) ? true : false;
+                if (allocated_with_custom && !custom_allocator && expected_custom_allocator_code != kVUIDUndefined) {
+                    // This check only verifies that custom allocation callbacks were provided to both Create and Destroy calls,
+                    // it cannot verify that these allocation callbacks are compatible with each other.
+                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
+                                    expected_custom_allocator_code,
+                                    "Custom allocator not specified while destroying %s obj 0x%" PRIxLEAST64
+                                    " but specified at creation.",
+                                    object_string[object_type], object_handle);
+                } else if (!allocated_with_custom && custom_allocator && expected_default_allocator_code != kVUIDUndefined) {
+                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
+                                    expected_default_allocator_code,
+                                    "Custom allocator specified while destroying %s obj 0x%" PRIxLEAST64
+                                    " but not specified at creation.",
+                                    object_string[object_type], object_handle);
+                }
+            }
+        }
+        return skip;
+    }
+
+#include "object_tracker.h"
+};
diff --git a/layers/object_tracker.h b/layers/object_tracker.h
deleted file mode 100644
index 6694c3f..0000000
--- a/layers/object_tracker.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Author: Mark Lobodzinski <mark@lunarg.com>
- * Author: Jon Ashburn <jon@lunarg.com>
- * Author: Tobin Ehlis <tobin@lunarg.com>
- */
-
-#include <mutex>
-#include <cinttypes>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "vk_loader_platform.h"
-#include "vulkan/vulkan.h"
-#include "vk_layer_config.h"
-#include "vk_layer_data.h"
-#include "vk_layer_logging.h"
-#include "vk_object_types.h"
-#include "vulkan/vk_layer.h"
-#include "vk_enum_string_helper.h"
-#include "vk_layer_extension_utils.h"
-#include "vk_layer_utils.h"
-#include "vulkan/vk_layer.h"
-#include "vk_dispatch_table_helper.h"
-#include "vk_extension_helper.h"
-
-namespace object_tracker {
-
-// Suppress unused warning on Linux
-#if defined(__GNUC__)
-#define DECORATE_UNUSED __attribute__((unused))
-#else
-#define DECORATE_UNUSED
-#endif
-
-// clang-format off
-static const char DECORATE_UNUSED *kVUID_ObjectTracker_Info = "UNASSIGNED-ObjectTracker-Info";
-static const char DECORATE_UNUSED *kVUID_ObjectTracker_InternalError = "UNASSIGNED-ObjectTracker-InternalError";
-static const char DECORATE_UNUSED *kVUID_ObjectTracker_ObjectLeak =    "UNASSIGNED-ObjectTracker-ObjectLeak";
-static const char DECORATE_UNUSED *kVUID_ObjectTracker_UnknownObject = "UNASSIGNED-ObjectTracker-UnknownObject";
-// clang-format on
-
-#undef DECORATE_UNUSED
-
-// Object Status -- used to track state of individual objects
-typedef VkFlags ObjectStatusFlags;
-enum ObjectStatusFlagBits {
-    OBJSTATUS_NONE = 0x00000000,                      // No status is set
-    OBJSTATUS_FENCE_IS_SUBMITTED = 0x00000001,        // Fence has been submitted
-    OBJSTATUS_VIEWPORT_BOUND = 0x00000002,            // Viewport state object has been bound
-    OBJSTATUS_RASTER_BOUND = 0x00000004,              // Viewport state object has been bound
-    OBJSTATUS_COLOR_BLEND_BOUND = 0x00000008,         // Viewport state object has been bound
-    OBJSTATUS_DEPTH_STENCIL_BOUND = 0x00000010,       // Viewport state object has been bound
-    OBJSTATUS_GPU_MEM_MAPPED = 0x00000020,            // Memory object is currently mapped
-    OBJSTATUS_COMMAND_BUFFER_SECONDARY = 0x00000040,  // Command Buffer is of type SECONDARY
-    OBJSTATUS_CUSTOM_ALLOCATOR = 0x00000080,          // Allocated with custom allocator
-};
-
-// Object and state information structure
-struct ObjTrackState {
-    uint64_t handle;               // Object handle (new)
-    VulkanObjectType object_type;  // Object type identifier
-    ObjectStatusFlags status;      // Object state
-    uint64_t parent_object;        // Parent object
-};
-
-// Track Queue information
-struct ObjTrackQueueInfo {
-    uint32_t queue_node_index;
-    VkQueue queue;
-};
-
-typedef std::unordered_map<uint64_t, ObjTrackState *> object_map_type;
-
-struct layer_data {
-    VkInstance instance;
-    VkPhysicalDevice physical_device;
-
-    uint64_t num_objects[kVulkanObjectTypeMax + 1];
-    uint64_t num_total_objects;
-    std::unordered_set<std::string> device_extension_set;
-
-    debug_report_data *report_data;
-    std::vector<VkDebugReportCallbackEXT> logging_callback;
-    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
-    // The following are for keeping track of the temporary callbacks that can
-    // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_report_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
-    VkDebugReportCallbackEXT *tmp_report_callbacks;
-    uint32_t num_tmp_debug_messengers;
-    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
-    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
-
-    std::vector<VkQueueFamilyProperties> queue_family_properties;
-
-    // Vector of unordered_maps per object type to hold ObjTrackState info
-    std::vector<object_map_type> object_map;
-    // Special-case map for swapchain images
-    std::unordered_map<uint64_t, ObjTrackState *> swapchainImageMap;
-    // Map of queue information structures, one per queue
-    std::unordered_map<VkQueue, ObjTrackQueueInfo *> queue_info_map;
-
-    VkLayerDispatchTable device_dispatch_table;
-    VkLayerInstanceDispatchTable instance_dispatch_table;
-    // Default constructor
-    layer_data()
-        : instance(nullptr),
-          physical_device(nullptr),
-          num_objects{},
-          num_total_objects(0),
-          report_data(nullptr),
-          num_tmp_report_callbacks(0),
-          tmp_report_create_infos(nullptr),
-          tmp_report_callbacks(nullptr),
-          num_tmp_debug_messengers(0),
-          tmp_messenger_create_infos(nullptr),
-          tmp_debug_messengers(nullptr),
-          object_map{},
-          device_dispatch_table{},
-          instance_dispatch_table{} {
-        object_map.resize(kVulkanObjectTypeMax + 1);
-    }
-};
-
-extern std::unordered_map<void *, layer_data *> layer_data_map;
-extern std::mutex global_lock;
-extern uint64_t object_track_index;
-extern uint32_t loader_layer_if_version;
-extern const std::unordered_map<std::string, void *> name_to_funcptr_map;
-
-void DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, const std::string &error_code);
-void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type);
-void CreateQueue(VkDevice device, VkQueue vkObj);
-void AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue);
-void ValidateQueueFlags(VkQueue queue, const char *function);
-void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer,
-                           VkCommandBufferLevel level);
-void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set);
-void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain);
-void ReportUndestroyedObjects(VkDevice device, const std::string &error_code);
-void DestroyUndestroyedObjects(VkDevice device);
-bool ValidateDeviceObject(uint64_t device_handle, const std::string &invalid_handle_code, const std::string &wrong_device_code);
-
-template <typename T1, typename T2>
-bool ValidateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, bool null_allowed,
-                    const std::string &invalid_handle_code, const std::string &wrong_device_code) {
-    if (null_allowed && (object == VK_NULL_HANDLE)) {
-        return false;
-    }
-    auto object_handle = HandleToUint64(object);
-
-    if (object_type == kVulkanObjectTypeDevice) {
-        return ValidateDeviceObject(object_handle, invalid_handle_code, wrong_device_code);
-    }
-
-    VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
-
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
-    // Look for object in device object map
-    if (device_data->object_map[object_type].find(object_handle) == device_data->object_map[object_type].end()) {
-        // If object is an image, also look for it in the swapchain image map
-        if ((object_type != kVulkanObjectTypeImage) ||
-            (device_data->swapchainImageMap.find(object_handle) == device_data->swapchainImageMap.end())) {
-            // Object not found, look for it in other device object maps
-            for (auto other_device_data : layer_data_map) {
-                if (other_device_data.second != device_data) {
-                    if (other_device_data.second->object_map[object_type].find(object_handle) !=
-                            other_device_data.second->object_map[object_type].end() ||
-                        (object_type == kVulkanObjectTypeImage && other_device_data.second->swapchainImageMap.find(object_handle) !=
-                                                                      other_device_data.second->swapchainImageMap.end())) {
-                        // Object found on other device, report an error if object has a device parent error code
-                        if ((wrong_device_code != kVUIDUndefined) && (object_type != kVulkanObjectTypeSurfaceKHR)) {
-                            return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type,
-                                           object_handle, wrong_device_code,
-                                           "Object 0x%" PRIxLEAST64
-                                           " was not created, allocated or retrieved from the correct device.",
-                                           object_handle);
-                        } else {
-                            return false;
-                        }
-                    }
-                }
-            }
-            // Report an error if object was not found anywhere
-            return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
-                           invalid_handle_code, "Invalid %s Object 0x%" PRIxLEAST64 ".", object_string[object_type], object_handle);
-        }
-    }
-    return false;
-}
-
-template <typename T1, typename T2>
-void CreateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator) {
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
-
-    auto object_handle = HandleToUint64(object);
-    bool custom_allocator = pAllocator != nullptr;
-
-    if (!instance_data->object_map[object_type].count(object_handle)) {
-        VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
-        log_msg(instance_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle,
-                kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64, object_track_index++,
-                object_string[object_type], object_handle);
-
-        ObjTrackState *pNewObjNode = new ObjTrackState;
-        pNewObjNode->object_type = object_type;
-        pNewObjNode->status = custom_allocator ? OBJSTATUS_CUSTOM_ALLOCATOR : OBJSTATUS_NONE;
-        pNewObjNode->handle = object_handle;
-
-        instance_data->object_map[object_type][object_handle] = pNewObjNode;
-        instance_data->num_objects[object_type]++;
-        instance_data->num_total_objects++;
-    }
-}
-
-template <typename T1, typename T2>
-void DestroyObjectSilently(T1 dispatchable_object, T2 object, VulkanObjectType object_type) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
-
-    auto object_handle = HandleToUint64(object);
-    assert(object_handle != VK_NULL_HANDLE);
-
-    auto item = device_data->object_map[object_type].find(object_handle);
-    assert(item != device_data->object_map[object_type].end());
-
-    ObjTrackState *pNode = item->second;
-    assert(device_data->num_total_objects > 0);
-
-    device_data->num_total_objects--;
-    assert(device_data->num_objects[pNode->object_type] > 0);
-
-    device_data->num_objects[pNode->object_type]--;
-
-    delete pNode;
-    device_data->object_map[object_type].erase(item);
-}
-
-template <typename T1, typename T2>
-void DestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator,
-                   const std::string &expected_custom_allocator_code, const std::string &expected_default_allocator_code) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
-
-    auto object_handle = HandleToUint64(object);
-    bool custom_allocator = pAllocator != nullptr;
-    VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[object_type];
-
-    if (object_handle != VK_NULL_HANDLE) {
-        auto item = device_data->object_map[object_type].find(object_handle);
-        if (item != device_data->object_map[object_type].end()) {
-            ObjTrackState *pNode = item->second;
-
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle,
-                    kVUID_ObjectTracker_Info,
-                    "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
-                    object_string[object_type], HandleToUint64(object), device_data->num_total_objects - 1,
-                    device_data->num_objects[pNode->object_type] - 1, object_string[object_type]);
-
-            auto allocated_with_custom = (pNode->status & OBJSTATUS_CUSTOM_ALLOCATOR) ? true : false;
-            if (allocated_with_custom && !custom_allocator && expected_custom_allocator_code != kVUIDUndefined) {
-                // This check only verifies that custom allocation callbacks were provided to both Create and Destroy calls,
-                // it cannot verify that these allocation callbacks are compatible with each other.
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
-                        expected_custom_allocator_code,
-                        "Custom allocator not specified while destroying %s obj 0x%" PRIxLEAST64 " but specified at creation.",
-                        object_string[object_type], object_handle);
-            } else if (!allocated_with_custom && custom_allocator && expected_default_allocator_code != kVUIDUndefined) {
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, object_handle,
-                        expected_default_allocator_code,
-                        "Custom allocator specified while destroying %s obj 0x%" PRIxLEAST64 " but not specified at creation.",
-                        object_string[object_type], object_handle);
-            }
-
-            DestroyObjectSilently(dispatchable_object, object, object_type);
-        } else {
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, object_handle,
-                    kVUID_ObjectTracker_UnknownObject,
-                    "Unable to remove %s obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?",
-                    object_string[object_type], object_handle);
-        }
-    }
-}
-
-}  // namespace object_tracker
diff --git a/layers/object_tracker_utils.cpp b/layers/object_tracker_utils.cpp
index e3ac38a..6d5c9ae 100644
--- a/layers/object_tracker_utils.cpp
+++ b/layers/object_tracker_utils.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,77 +20,62 @@
  * Author: Tobin Ehlis <tobin@lunarg.com>
  */
 
-#include "object_tracker.h"
+#include "chassis.h"
 
-namespace object_tracker {
+#include "object_lifetime_validation.h"
 
-std::unordered_map<void *, layer_data *> layer_data_map;
-std::mutex global_lock;
 uint64_t object_track_index = 0;
-uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-
-void InitObjectTracker(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_report_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_object_tracker");
-    layer_debug_messenger_actions(my_data->report_data, my_data->logging_messenger, pAllocator, "lunarg_object_tracker");
-}
 
 // Add new queue to head of global queue list
-void AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    auto queueItem = device_data->queue_info_map.find(queue);
-    if (queueItem == device_data->queue_info_map.end()) {
+void ObjectLifetimes::AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue) {
+    auto queueItem = queue_info_map.find(queue);
+    if (queueItem == queue_info_map.end()) {
         ObjTrackQueueInfo *p_queue_info = new ObjTrackQueueInfo;
         if (p_queue_info != NULL) {
             memset(p_queue_info, 0, sizeof(ObjTrackQueueInfo));
             p_queue_info->queue = queue;
             p_queue_info->queue_node_index = queue_node_index;
-            device_data->queue_info_map[queue] = p_queue_info;
+            queue_info_map[queue] = p_queue_info;
         } else {
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
-                    HandleToUint64(queue), kVUID_ObjectTracker_InternalError,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, HandleToUint64(queue),
+                    kVUID_ObjectTracker_InternalError,
                     "ERROR:  VK_ERROR_OUT_OF_HOST_MEMORY -- could not allocate memory for Queue Information");
         }
     }
 }
 
 // Destroy memRef lists and free all memory
-void DestroyQueueDataStructures(VkDevice device) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    for (auto queue_item : device_data->queue_info_map) {
+void ObjectLifetimes::DestroyQueueDataStructures(VkDevice device) {
+    for (auto queue_item : queue_info_map) {
         delete queue_item.second;
     }
-    device_data->queue_info_map.clear();
+    queue_info_map.clear();
 
     // Destroy the items in the queue map
-    auto queue = device_data->object_map[kVulkanObjectTypeQueue].begin();
-    while (queue != device_data->object_map[kVulkanObjectTypeQueue].end()) {
+    auto queue = object_map[kVulkanObjectTypeQueue].begin();
+    while (queue != object_map[kVulkanObjectTypeQueue].end()) {
         uint32_t obj_index = queue->second->object_type;
-        assert(device_data->num_total_objects > 0);
-        device_data->num_total_objects--;
-        assert(device_data->num_objects[obj_index] > 0);
-        device_data->num_objects[obj_index]--;
-        log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
-                queue->second->handle, kVUID_ObjectTracker_Info,
-                "OBJ_STAT Destroy Queue obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " Queue objs).",
-                queue->second->handle, device_data->num_total_objects, device_data->num_objects[obj_index]);
+        assert(num_total_objects > 0);
+        num_total_objects--;
+        assert(num_objects[obj_index] > 0);
+        num_objects[obj_index]--;
+        log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, queue->second->handle,
+                kVUID_ObjectTracker_Info, "OBJ_STAT Destroy Queue obj %s (%" PRIu64 " total objs remain & %" PRIu64 " Queue objs).",
+                report_data->FormatHandle(queue->second->handle).c_str(), num_total_objects, num_objects[obj_index]);
         delete queue->second;
-        queue = device_data->object_map[kVulkanObjectTypeQueue].erase(queue);
+        queue = object_map[kVulkanObjectTypeQueue].erase(queue);
     }
 }
 
 // Check Queue type flags for selected queue operations
-void ValidateQueueFlags(VkQueue queue, const char *function) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    auto queue_item = device_data->queue_info_map.find(queue);
-    if (queue_item != device_data->queue_info_map.end()) {
+void ObjectLifetimes::ValidateQueueFlags(VkQueue queue, const char *function) {
+    auto queue_item = queue_info_map.find(queue);
+    if (queue_item != queue_info_map.end()) {
         ObjTrackQueueInfo *pQueueInfo = queue_item->second;
         if (pQueueInfo != NULL) {
-            layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(device_data->physical_device), layer_data_map);
-            if ((instance_data->queue_family_properties[pQueueInfo->queue_node_index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) ==
-                0) {
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
-                        HandleToUint64(queue), "VUID-vkQueueBindSparse-queuetype",
+            if ((queue_family_properties[pQueueInfo->queue_node_index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) == 0) {
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, HandleToUint64(queue),
+                        "VUID-vkQueueBindSparse-queuetype",
                         "Attempting %s on a non-memory-management capable queue -- VK_QUEUE_SPARSE_BINDING_BIT not set.", function);
             }
         }
@@ -100,28 +85,22 @@
 // Look for this device object in any of the instance child devices lists.
 // NOTE: This is of dubious value. In most circumstances Vulkan will die a flaming death if a dispatchable object is invalid.
 // However, if this layer is loaded first and GetProcAddress is used to make API calls, it will detect bad DOs.
-bool ValidateDeviceObject(uint64_t device_handle, const std::string &invalid_handle_code, const std::string &wrong_device_code) {
-    VkInstance last_instance = nullptr;
-    for (auto layer_data : layer_data_map) {
-        for (auto object : layer_data.second->object_map[kVulkanObjectTypeDevice]) {
-            // Grab last instance to use for possible error message
-            last_instance = layer_data.second->instance;
-            if (object.second->handle == device_handle) return false;
-        }
+bool ObjectLifetimes::ValidateDeviceObject(uint64_t device_handle, const char *invalid_handle_code, const char *wrong_device_code) {
+    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    auto instance_object_lifetime_data = GetObjectLifetimeData(instance_data->object_dispatch);
+    for (auto object : instance_object_lifetime_data->object_map[kVulkanObjectTypeDevice]) {
+        if (object.second->handle == device_handle) return false;
     }
-
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(last_instance), layer_data_map);
-    return log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device_handle,
-                   invalid_handle_code, "Invalid Device Object 0x%" PRIxLEAST64 ".", device_handle);
+    return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device_handle,
+                   invalid_handle_code, "Invalid Device Object %s.", report_data->FormatHandle(device_handle).c_str());
 }
 
-void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer,
-                           VkCommandBufferLevel level) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-            HandleToUint64(command_buffer), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64,
-            object_track_index++, "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT", HandleToUint64(command_buffer));
+void ObjectLifetimes::AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, const VkCommandBuffer command_buffer,
+                                            VkCommandBufferLevel level) {
+    log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            HandleToUint64(command_buffer), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object %s.",
+            object_track_index++, "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT",
+            report_data->FormatHandle(command_buffer).c_str());
 
     ObjTrackState *pNewObjNode = new ObjTrackState;
     pNewObjNode->object_type = kVulkanObjectTypeCommandBuffer;
@@ -132,76 +111,81 @@
     } else {
         pNewObjNode->status = OBJSTATUS_NONE;
     }
-    device_data->object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)] = pNewObjNode;
-    device_data->num_objects[kVulkanObjectTypeCommandBuffer]++;
-    device_data->num_total_objects++;
+    object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)] = pNewObjNode;
+    num_objects[kVulkanObjectTypeCommandBuffer]++;
+    num_total_objects++;
 }
 
-bool ValidateCommandBuffer(VkDevice device, VkCommandPool command_pool, VkCommandBuffer command_buffer) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool ObjectLifetimes::ValidateCommandBuffer(VkDevice device, VkCommandPool command_pool, VkCommandBuffer command_buffer) {
     bool skip = false;
     uint64_t object_handle = HandleToUint64(command_buffer);
-    if (device_data->object_map[kVulkanObjectTypeCommandBuffer].find(object_handle) !=
-        device_data->object_map[kVulkanObjectTypeCommandBuffer].end()) {
-        ObjTrackState *pNode = device_data->object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)];
+    if (object_map[kVulkanObjectTypeCommandBuffer].find(object_handle) != object_map[kVulkanObjectTypeCommandBuffer].end()) {
+        ObjTrackState *pNode = object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)];
 
         if (pNode->parent_object != HandleToUint64(command_pool)) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                            object_handle, "VUID-vkFreeCommandBuffers-pCommandBuffers-parent",
-                            "FreeCommandBuffers is attempting to free Command Buffer 0x%" PRIxLEAST64
-                            " belonging to Command Pool 0x%" PRIxLEAST64 " from pool 0x%" PRIxLEAST64 ").",
-                            HandleToUint64(command_buffer), pNode->parent_object, HandleToUint64(command_pool));
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, object_handle,
+                        "VUID-vkFreeCommandBuffers-pCommandBuffers-parent",
+                        "FreeCommandBuffers is attempting to free Command Buffer %s belonging to Command Pool %s from pool %s).",
+                        report_data->FormatHandle(command_buffer).c_str(), report_data->FormatHandle(pNode->parent_object).c_str(),
+                        report_data->FormatHandle(command_pool).c_str());
         }
     } else {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
-                        object_handle, "VUID-vkFreeCommandBuffers-pCommandBuffers-00048", "Invalid %s Object 0x%" PRIxLEAST64 ".",
-                        object_string[kVulkanObjectTypeCommandBuffer], object_handle);
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, object_handle,
+                        "VUID-vkFreeCommandBuffers-pCommandBuffers-00048", "Invalid %s Object %s.",
+                        object_string[kVulkanObjectTypeCommandBuffer], report_data->FormatHandle(object_handle).c_str());
     }
     return skip;
 }
 
-void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-            HandleToUint64(descriptor_set), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64,
-            object_track_index++, "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT", HandleToUint64(descriptor_set));
+void ObjectLifetimes::AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set) {
+    log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+            HandleToUint64(descriptor_set), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object %s.",
+            object_track_index++, "VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT",
+            report_data->FormatHandle(descriptor_set).c_str());
 
     ObjTrackState *pNewObjNode = new ObjTrackState;
     pNewObjNode->object_type = kVulkanObjectTypeDescriptorSet;
     pNewObjNode->status = OBJSTATUS_NONE;
     pNewObjNode->handle = HandleToUint64(descriptor_set);
     pNewObjNode->parent_object = HandleToUint64(descriptor_pool);
-    device_data->object_map[kVulkanObjectTypeDescriptorSet][HandleToUint64(descriptor_set)] = pNewObjNode;
-    device_data->num_objects[kVulkanObjectTypeDescriptorSet]++;
-    device_data->num_total_objects++;
+    object_map[kVulkanObjectTypeDescriptorSet][HandleToUint64(descriptor_set)] = pNewObjNode;
+    num_objects[kVulkanObjectTypeDescriptorSet]++;
+    num_total_objects++;
+
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptor_pool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        ObjTrackState *pPoolNode = itr->second;
+        pPoolNode->child_objects->insert(HandleToUint64(descriptor_set));
+    }
 }
 
-bool ValidateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool ObjectLifetimes::ValidateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set) {
     bool skip = false;
     uint64_t object_handle = HandleToUint64(descriptor_set);
-    auto dsItem = device_data->object_map[kVulkanObjectTypeDescriptorSet].find(object_handle);
-    if (dsItem != device_data->object_map[kVulkanObjectTypeDescriptorSet].end()) {
+    auto dsItem = object_map[kVulkanObjectTypeDescriptorSet].find(object_handle);
+    if (dsItem != object_map[kVulkanObjectTypeDescriptorSet].end()) {
         ObjTrackState *pNode = dsItem->second;
 
         if (pNode->parent_object != HandleToUint64(descriptor_pool)) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                            object_handle, "VUID-vkFreeDescriptorSets-pDescriptorSets-parent",
-                            "FreeDescriptorSets is attempting to free descriptorSet 0x%" PRIxLEAST64
-                            " belonging to Descriptor Pool 0x%" PRIxLEAST64 " from pool 0x%" PRIxLEAST64 ").",
-                            HandleToUint64(descriptor_set), pNode->parent_object, HandleToUint64(descriptor_pool));
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, object_handle,
+                        "VUID-vkFreeDescriptorSets-pDescriptorSets-parent",
+                        "FreeDescriptorSets is attempting to free descriptorSet %s"
+                        " belonging to Descriptor Pool %s from pool %s).",
+                        report_data->FormatHandle(descriptor_set).c_str(), report_data->FormatHandle(pNode->parent_object).c_str(),
+                        report_data->FormatHandle(descriptor_pool).c_str());
         }
     } else {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                        object_handle, "VUID-vkFreeDescriptorSets-pDescriptorSets-00310", "Invalid %s Object 0x%" PRIxLEAST64 ".",
-                        object_string[kVulkanObjectTypeDescriptorSet], object_handle);
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, object_handle,
+                        "VUID-vkFreeDescriptorSets-pDescriptorSets-00310", "Invalid %s Object %s.",
+                        object_string[kVulkanObjectTypeDescriptorSet], report_data->FormatHandle(object_handle).c_str());
     }
     return skip;
 }
 
 template <typename DispObj>
-static bool ValidateDescriptorWrite(DispObj disp, VkWriteDescriptorSet const *desc, bool isPush) {
+bool ObjectLifetimes::ValidateDescriptorWrite(DispObj disp, VkWriteDescriptorSet const *desc, bool isPush) {
     bool skip = false;
 
     if (!isPush && desc->dstSet) {
@@ -241,43 +225,34 @@
     return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
-                                                   VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
-                                                   const VkWriteDescriptorSet *pDescriptorWrites) {
+bool ObjectLifetimes::PreCallValidateCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
+                                                             VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
+                                                             const VkWriteDescriptorSet *pDescriptorWrites) {
     bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |=
-            ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false,
+    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false,
                            "VUID-vkCmdPushDescriptorSetKHR-commandBuffer-parameter", "VUID-vkCmdPushDescriptorSetKHR-commonparent");
-        skip |= ValidateObject(commandBuffer, layout, kVulkanObjectTypePipelineLayout, false,
-                               "VUID-vkCmdPushDescriptorSetKHR-layout-parameter", "VUID-vkCmdPushDescriptorSetKHR-commonparent");
-        if (pDescriptorWrites) {
-            for (uint32_t index0 = 0; index0 < descriptorWriteCount; ++index0) {
-                skip |= ValidateDescriptorWrite(commandBuffer, &pDescriptorWrites[index0], true);
-            }
+    skip |= ValidateObject(commandBuffer, layout, kVulkanObjectTypePipelineLayout, false,
+                           "VUID-vkCmdPushDescriptorSetKHR-layout-parameter", "VUID-vkCmdPushDescriptorSetKHR-commonparent");
+    if (pDescriptorWrites) {
+        for (uint32_t index0 = 0; index0 < descriptorWriteCount; ++index0) {
+            skip |= ValidateDescriptorWrite(commandBuffer, &pDescriptorWrites[index0], true);
         }
     }
-    if (skip) return;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    device_data->device_dispatch_table.CmdPushDescriptorSetKHR(commandBuffer, pipelineBindPoint, layout, set, descriptorWriteCount,
-                                                               pDescriptorWrites);
+    return skip;
 }
 
-void CreateQueue(VkDevice device, VkQueue vkObj) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
-            HandleToUint64(vkObj), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64,
-            object_track_index++, "VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT", HandleToUint64(vkObj));
+void ObjectLifetimes::CreateQueue(VkDevice device, VkQueue vkObj) {
+    log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, HandleToUint64(vkObj),
+            kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object %s", object_track_index++,
+            "VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT", report_data->FormatHandle(vkObj).c_str());
 
     ObjTrackState *p_obj_node = NULL;
-    auto queue_item = device_data->object_map[kVulkanObjectTypeQueue].find(HandleToUint64(vkObj));
-    if (queue_item == device_data->object_map[kVulkanObjectTypeQueue].end()) {
+    auto queue_item = object_map[kVulkanObjectTypeQueue].find(HandleToUint64(vkObj));
+    if (queue_item == object_map[kVulkanObjectTypeQueue].end()) {
         p_obj_node = new ObjTrackState;
-        device_data->object_map[kVulkanObjectTypeQueue][HandleToUint64(vkObj)] = p_obj_node;
-        device_data->num_objects[kVulkanObjectTypeQueue]++;
-        device_data->num_total_objects++;
+        object_map[kVulkanObjectTypeQueue][HandleToUint64(vkObj)] = p_obj_node;
+        num_objects[kVulkanObjectTypeQueue]++;
+        num_total_objects++;
     } else {
         p_obj_node = queue_item->second;
     }
@@ -286,637 +261,294 @@
     p_obj_node->handle = HandleToUint64(vkObj);
 }
 
-void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
-    log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
-            HandleToUint64(swapchain_image), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object 0x%" PRIxLEAST64,
-            object_track_index++, "SwapchainImage", HandleToUint64(swapchain_image));
+void ObjectLifetimes::CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain) {
+    log_msg(report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
+            HandleToUint64(swapchain_image), kVUID_ObjectTracker_Info, "OBJ[0x%" PRIxLEAST64 "] : CREATE %s object %s.",
+            object_track_index++, "SwapchainImage", report_data->FormatHandle(swapchain_image).c_str());
 
     ObjTrackState *pNewObjNode = new ObjTrackState;
     pNewObjNode->object_type = kVulkanObjectTypeImage;
     pNewObjNode->status = OBJSTATUS_NONE;
     pNewObjNode->handle = HandleToUint64(swapchain_image);
     pNewObjNode->parent_object = HandleToUint64(swapchain);
-    device_data->swapchainImageMap[HandleToUint64(swapchain_image)] = pNewObjNode;
+    swapchainImageMap[HandleToUint64(swapchain_image)] = pNewObjNode;
 }
 
-void DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, const std::string &error_code) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    for (const auto &item : device_data->object_map[object_type]) {
+bool ObjectLifetimes::DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, const std::string &error_code) {
+    bool skip = false;
+    for (const auto &item : object_map[object_type]) {
         const ObjTrackState *object_info = item.second;
-        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], object_info->handle,
-                error_code, "OBJ ERROR : For device 0x%" PRIxLEAST64 ", %s object 0x%" PRIxLEAST64 " has not been destroyed.",
-                HandleToUint64(device), object_string[object_type], object_info->handle);
+        skip |=
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], object_info->handle, error_code,
+                    "OBJ ERROR : For device %s, %s object %s has not been destroyed.", report_data->FormatHandle(device).c_str(),
+                    object_string[object_type], report_data->FormatHandle(object_info->handle).c_str());
     }
+    return skip;
 }
 
-void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    while (!device_data->object_map[object_type].empty()) {
-        auto item = device_data->object_map[object_type].begin();
+void ObjectLifetimes::DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type) {
+    while (!object_map[object_type].empty()) {
+        auto item = object_map[object_type].begin();
 
         ObjTrackState *object_info = item->second;
-        DestroyObjectSilently(device, object_info->handle, object_type);
+        DestroyObjectSilently(object_info->handle, object_type);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    std::unique_lock<std::mutex> lock(global_lock);
+bool ObjectLifetimes::PreCallValidateDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
+    bool skip = false;
 
-    dispatch_key key = get_dispatch_key(instance);
-    layer_data *instance_data = GetLayerDataPtr(key, layer_data_map);
+    // We validate here for coverage, though we'd not have made it this for with a bad instance.
+    skip |= ValidateObject(instance, instance, kVulkanObjectTypeInstance, true, "VUID-vkDestroyInstance-instance-parameter",
+                           kVUIDUndefined);
 
-    // Enable the temporary callback(s) here to catch cleanup issues:
-    if (instance_data->num_tmp_debug_messengers > 0) {
-        layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                          instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
-    }
-    if (instance_data->num_tmp_report_callbacks > 0) {
-        layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                          instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
-    }
-
-    // TODO: The instance handle can not be validated here. The loader will likely have to validate it.
-    ValidateObject(instance, instance, kVulkanObjectTypeInstance, true, "VUID-vkDestroyInstance-instance-parameter",
-                   kVUIDUndefined);
-
-    // Destroy physical devices
-    for (auto iit = instance_data->object_map[kVulkanObjectTypePhysicalDevice].begin();
-         iit != instance_data->object_map[kVulkanObjectTypePhysicalDevice].end();) {
-        ObjTrackState *pNode = iit->second;
-        VkPhysicalDevice physical_device = reinterpret_cast<VkPhysicalDevice>(pNode->handle);
-
-        DestroyObject(instance, physical_device, kVulkanObjectTypePhysicalDevice, nullptr, kVUIDUndefined, kVUIDUndefined);
-        iit = instance_data->object_map[kVulkanObjectTypePhysicalDevice].begin();
-    }
-
-    // Destroy child devices
-    for (auto iit = instance_data->object_map[kVulkanObjectTypeDevice].begin();
-         iit != instance_data->object_map[kVulkanObjectTypeDevice].end();) {
-        ObjTrackState *pNode = iit->second;
+    // Validate that child devices have been destroyed
+    for (const auto &iit : object_map[kVulkanObjectTypeDevice]) {
+        ObjTrackState *pNode = iit.second;
 
         VkDevice device = reinterpret_cast<VkDevice>(pNode->handle);
         VkDebugReportObjectTypeEXT debug_object_type = get_debug_report_enum[pNode->object_type];
 
-        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, pNode->handle,
-                kVUID_ObjectTracker_ObjectLeak, "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.",
-                string_VkDebugReportObjectTypeEXT(debug_object_type), pNode->handle);
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, debug_object_type, pNode->handle,
+                        kVUID_ObjectTracker_ObjectLeak, "OBJ ERROR : %s object %s has not been destroyed.",
+                        string_VkDebugReportObjectTypeEXT(debug_object_type), report_data->FormatHandle(pNode->handle).c_str());
 
         // Report any remaining objects in LL
-        ReportUndestroyedObjects(device, "VUID-vkDestroyInstance-instance-00629");
-        DestroyUndestroyedObjects(device);
+        skip |= ReportUndestroyedObjects(device, "VUID-vkDestroyInstance-instance-00629");
 
-        DestroyObject(instance, device, kVulkanObjectTypeDevice, pAllocator, "VUID-vkDestroyInstance-instance-00630",
-                      "VUID-vkDestroyInstance-instance-00631");
-        iit = instance_data->object_map[kVulkanObjectTypeDevice].begin();
+        skip |= ValidateDestroyObject(instance, device, kVulkanObjectTypeDevice, pAllocator,
+                                      "VUID-vkDestroyInstance-instance-00630", "VUID-vkDestroyInstance-instance-00631");
     }
 
-    instance_data->object_map[kVulkanObjectTypeDevice].clear();
-    instance_data->instance_dispatch_table.DestroyInstance(instance, pAllocator);
+    ValidateDestroyObject(instance, instance, kVulkanObjectTypeInstance, pAllocator, "VUID-vkDestroyInstance-instance-00630",
+                          "VUID-vkDestroyInstance-instance-00631");
 
-    // Disable and cleanup the temporary callback(s):
-    layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                       instance_data->tmp_debug_messengers);
-    layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                       instance_data->tmp_report_callbacks);
-    if (instance_data->num_tmp_debug_messengers > 0) {
-        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
-        instance_data->num_tmp_debug_messengers = 0;
-    }
-    if (instance_data->num_tmp_report_callbacks > 0) {
-        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
-        instance_data->num_tmp_report_callbacks = 0;
-    }
-
-    // Clean up logging callback, if any
-    while (instance_data->logging_messenger.size() > 0) {
-        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
-        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-        instance_data->logging_messenger.pop_back();
-    }
-    while (instance_data->logging_callback.size() > 0) {
-        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
-        instance_data->logging_callback.pop_back();
-    }
-
-    DestroyObject(instance, instance, kVulkanObjectTypeInstance, pAllocator, "VUID-vkDestroyInstance-instance-00630",
-                  "VUID-vkDestroyInstance-instance-00631");
-
-    layer_debug_utils_destroy_instance(instance_data->report_data);
-    FreeLayerDataPtr(key, layer_data_map);
-
-    lock.unlock();
+    return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    std::unique_lock<std::mutex> lock(global_lock);
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    ValidateObject(device, device, kVulkanObjectTypeDevice, true, "VUID-vkDestroyDevice-device-parameter", kVUIDUndefined);
-    DestroyObject(device_data->instance, device, kVulkanObjectTypeDevice, pAllocator, "VUID-vkDestroyDevice-device-00379",
-                  "VUID-vkDestroyDevice-device-00380");
+bool ObjectLifetimes::PreCallValidateEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
+                                                              VkPhysicalDevice *pPhysicalDevices) {
+    bool skip = ValidateObject(instance, instance, kVulkanObjectTypeInstance, false,
+                               "VUID-vkEnumeratePhysicalDevices-instance-parameter", kVUIDUndefined);
+    return skip;
+}
 
+void ObjectLifetimes::PostCallRecordEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
+                                                             VkPhysicalDevice *pPhysicalDevices, VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    if (pPhysicalDevices) {
+        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
+            CreateObject(instance, pPhysicalDevices[i], kVulkanObjectTypePhysicalDevice, nullptr);
+        }
+    }
+}
+
+void ObjectLifetimes::PreCallRecordDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
+    // Destroy physical devices
+    for (auto iit = object_map[kVulkanObjectTypePhysicalDevice].begin();
+         iit != object_map[kVulkanObjectTypePhysicalDevice].end();) {
+        ObjTrackState *pNode = iit->second;
+        VkPhysicalDevice physical_device = reinterpret_cast<VkPhysicalDevice>(pNode->handle);
+        RecordDestroyObject(instance, physical_device, kVulkanObjectTypePhysicalDevice);
+        iit = object_map[kVulkanObjectTypePhysicalDevice].begin();
+    }
+
+    // Destroy child devices
+    for (auto iit = object_map[kVulkanObjectTypeDevice].begin(); iit != object_map[kVulkanObjectTypeDevice].end();) {
+        ObjTrackState *pNode = iit->second;
+        VkDevice device = reinterpret_cast<VkDevice>(pNode->handle);
+        DestroyUndestroyedObjects(device);
+
+        RecordDestroyObject(instance, device, kVulkanObjectTypeDevice);
+        iit = object_map[kVulkanObjectTypeDevice].begin();
+    }
+
+    object_map[kVulkanObjectTypeDevice].clear();
+}
+
+void ObjectLifetimes::PostCallRecordDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
+    RecordDestroyObject(instance, instance, kVulkanObjectTypeInstance);
+}
+
+bool ObjectLifetimes::PreCallValidateDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    bool skip = false;
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, true, "VUID-vkDestroyDevice-device-parameter", kVUIDUndefined);
+    skip |= ValidateDestroyObject(physical_device, device, kVulkanObjectTypeDevice, pAllocator, "VUID-vkDestroyDevice-device-00379",
+                                  "VUID-vkDestroyDevice-device-00380");
     // Report any remaining objects associated with this VkDevice object in LL
-    ReportUndestroyedObjects(device, "VUID-vkDestroyDevice-device-00378");
+    skip |= ReportUndestroyedObjects(device, "VUID-vkDestroyDevice-device-00378");
+
+    return skip;
+}
+
+void ObjectLifetimes::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    auto instance_data = GetLayerDataPtr(get_dispatch_key(physical_device), layer_data_map);
+    ValidationObject *validation_data = GetValidationObject(instance_data->object_dispatch, LayerObjectTypeObjectTracker);
+    ObjectLifetimes *object_lifetimes = static_cast<ObjectLifetimes *>(validation_data);
+    object_lifetimes->RecordDestroyObject(physical_device, device, kVulkanObjectTypeDevice);
     DestroyUndestroyedObjects(device);
 
     // Clean up Queue's MemRef Linked Lists
     DestroyQueueDataStructures(device);
-
-    lock.unlock();
-    dispatch_key key = get_dispatch_key(device);
-    device_data->device_dispatch_table.DestroyDevice(device, pAllocator);
-    FreeLayerDataPtr(key, layer_data_map);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
-    std::unique_lock<std::mutex> lock(global_lock);
-    ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkGetDeviceQueue-device-parameter", kVUIDUndefined);
-    lock.unlock();
+bool ObjectLifetimes::PreCallValidateGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
+                                                    VkQueue *pQueue) {
+    bool skip = false;
+    skip |=
+        ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkGetDeviceQueue-device-parameter", kVUIDUndefined);
+    return skip;
+}
 
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    device_data->device_dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
-
-    lock.lock();
+void ObjectLifetimes::PostCallRecordGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
+                                                   VkQueue *pQueue) {
     CreateQueue(device, *pQueue);
     AddQueueInfo(device, queueFamilyIndex, *pQueue);
 }
 
-VKAPI_ATTR void VKAPI_CALL GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
-    std::unique_lock<std::mutex> lock(global_lock);
-    ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkGetDeviceQueue2-device-parameter", kVUIDUndefined);
-    lock.unlock();
-
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    device_data->device_dispatch_table.GetDeviceQueue2(device, pQueueInfo, pQueue);
-
-    lock.lock();
-    if (*pQueue != VK_NULL_HANDLE) {
-        CreateQueue(device, *pQueue);
-        AddQueueInfo(device, pQueueInfo->queueFamilyIndex, *pQueue);
-    }
+bool ObjectLifetimes::PreCallValidateGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
+    return ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkGetDeviceQueue2-device-parameter",
+                          kVUIDUndefined);
 }
 
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
-                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
-                                                const VkCopyDescriptorSet *pDescriptorCopies) {
+void ObjectLifetimes::PostCallRecordGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) {
+    CreateQueue(device, *pQueue);
+    AddQueueInfo(device, pQueueInfo->queueFamilyIndex, *pQueue);
+}
+
+bool ObjectLifetimes::PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                                          const VkWriteDescriptorSet *pDescriptorWrites,
+                                                          uint32_t descriptorCopyCount,
+                                                          const VkCopyDescriptorSet *pDescriptorCopies) {
     bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkUpdateDescriptorSets-device-parameter",
-                               kVUIDUndefined);
-        if (pDescriptorCopies) {
-            for (uint32_t idx0 = 0; idx0 < descriptorCopyCount; ++idx0) {
-                if (pDescriptorCopies[idx0].dstSet) {
-                    skip |= ValidateObject(device, pDescriptorCopies[idx0].dstSet, kVulkanObjectTypeDescriptorSet, false,
-                                           "VUID-VkCopyDescriptorSet-dstSet-parameter", "VUID-VkCopyDescriptorSet-commonparent");
-                }
-                if (pDescriptorCopies[idx0].srcSet) {
-                    skip |= ValidateObject(device, pDescriptorCopies[idx0].srcSet, kVulkanObjectTypeDescriptorSet, false,
-                                           "VUID-VkCopyDescriptorSet-srcSet-parameter", "VUID-VkCopyDescriptorSet-commonparent");
-                }
-            }
-        }
-        if (pDescriptorWrites) {
-            for (uint32_t idx1 = 0; idx1 < descriptorWriteCount; ++idx1) {
-                skip |= ValidateDescriptorWrite(device, &pDescriptorWrites[idx1], false);
-            }
-        }
-    }
-    if (skip) {
-        return;
-    }
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    device_data->device_dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
-                                                            pDescriptorCopies);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                                      const VkComputePipelineCreateInfo *pCreateInfos,
-                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkCreateComputePipelines-device-parameter",
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkUpdateDescriptorSets-device-parameter",
                            kVUIDUndefined);
-    if (pCreateInfos) {
-        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
-            if (pCreateInfos[idx0].basePipelineHandle) {
-                skip |=
-                    ValidateObject(device, pCreateInfos[idx0].basePipelineHandle, kVulkanObjectTypePipeline, true,
-                                   "VUID-VkComputePipelineCreateInfo-flags-00697", "VUID-VkComputePipelineCreateInfo-commonparent");
+    if (pDescriptorCopies) {
+        for (uint32_t idx0 = 0; idx0 < descriptorCopyCount; ++idx0) {
+            if (pDescriptorCopies[idx0].dstSet) {
+                skip |= ValidateObject(device, pDescriptorCopies[idx0].dstSet, kVulkanObjectTypeDescriptorSet, false,
+                                       "VUID-VkCopyDescriptorSet-dstSet-parameter", "VUID-VkCopyDescriptorSet-commonparent");
             }
-            if (pCreateInfos[idx0].layout) {
-                skip |= ValidateObject(device, pCreateInfos[idx0].layout, kVulkanObjectTypePipelineLayout, false,
-                                       "VUID-VkComputePipelineCreateInfo-layout-parameter",
-                                       "VUID-VkComputePipelineCreateInfo-commonparent");
-            }
-            if (pCreateInfos[idx0].stage.module) {
-                skip |= ValidateObject(device, pCreateInfos[idx0].stage.module, kVulkanObjectTypeShaderModule, false,
-                                       "VUID-VkPipelineShaderStageCreateInfo-module-parameter", kVUIDUndefined);
+            if (pDescriptorCopies[idx0].srcSet) {
+                skip |= ValidateObject(device, pDescriptorCopies[idx0].srcSet, kVulkanObjectTypeDescriptorSet, false,
+                                       "VUID-VkCopyDescriptorSet-srcSet-parameter", "VUID-VkCopyDescriptorSet-commonparent");
             }
         }
     }
-    if (pipelineCache) {
-        skip |= ValidateObject(device, pipelineCache, kVulkanObjectTypePipelineCache, true,
-                               "VUID-vkCreateComputePipelines-pipelineCache-parameter",
-                               "VUID-vkCreateComputePipelines-pipelineCache-parent");
-    }
-    lock.unlock();
-    if (skip) {
-        for (uint32_t i = 0; i < createInfoCount; i++) {
-            pPipelines[i] = VK_NULL_HANDLE;
-        }
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = device_data->device_dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount,
-                                                                                pCreateInfos, pAllocator, pPipelines);
-
-    lock.lock();
-    for (uint32_t idx1 = 0; idx1 < createInfoCount; ++idx1) {
-        if (pPipelines[idx1] != VK_NULL_HANDLE) {
-            CreateObject(device, pPipelines[idx1], kVulkanObjectTypePipeline, pAllocator);
+    if (pDescriptorWrites) {
+        for (uint32_t idx1 = 0; idx1 < descriptorWriteCount; ++idx1) {
+            skip |= ValidateDescriptorWrite(device, &pDescriptorWrites[idx1], false);
         }
     }
-    lock.unlock();
-    return result;
+    return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
-                                                   VkDescriptorPoolResetFlags flags) {
+bool ObjectLifetimes::PreCallValidateResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                         VkDescriptorPoolResetFlags flags) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkResetDescriptorPool-device-parameter",
                            kVUIDUndefined);
     skip |=
         ValidateObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool, false,
                        "VUID-vkResetDescriptorPool-descriptorPool-parameter", "VUID-vkResetDescriptorPool-descriptorPool-parent");
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    // A DescriptorPool's descriptor sets are implicitly deleted when the pool is reset.
-    // Remove this pool's descriptor sets from our descriptorSet map.
-    auto itr = device_data->object_map[kVulkanObjectTypeDescriptorSet].begin();
-    while (itr != device_data->object_map[kVulkanObjectTypeDescriptorSet].end()) {
-        ObjTrackState *pNode = (*itr).second;
-        auto del_itr = itr++;
-        if (pNode->parent_object == HandleToUint64(descriptorPool)) {
-            DestroyObject(device, (VkDescriptorSet)((*del_itr).first), kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined,
-                          kVUIDUndefined);
+
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptorPool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        ObjTrackState *pPoolNode = itr->second;
+        for (auto set : *pPoolNode->child_objects) {
+            skip |= ValidateDestroyObject(device, (VkDescriptorSet)set, kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined,
+                                          kVUIDUndefined);
         }
     }
-    lock.unlock();
-    VkResult result = device_data->device_dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
-    return result;
+    return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer command_buffer, const VkCommandBufferBeginInfo *begin_info) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(command_buffer), layer_data_map);
+void ObjectLifetimes::PreCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                       VkDescriptorPoolResetFlags flags) {
+    // A DescriptorPool's descriptor sets are implicitly deleted when the pool is reset. Remove this pool's descriptor sets from
+    // our descriptorSet map.
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptorPool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        ObjTrackState *pPoolNode = itr->second;
+        for (auto set : *pPoolNode->child_objects) {
+            RecordDestroyObject(device, (VkDescriptorSet)set, kVulkanObjectTypeDescriptorSet);
+        }
+        pPoolNode->child_objects->clear();
+    }
+}
+
+bool ObjectLifetimes::PreCallValidateBeginCommandBuffer(VkCommandBuffer command_buffer,
+                                                        const VkCommandBufferBeginInfo *begin_info) {
     bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(command_buffer, command_buffer, kVulkanObjectTypeCommandBuffer, false,
-                               "VUID-vkBeginCommandBuffer-commandBuffer-parameter", kVUIDUndefined);
-        if (begin_info) {
-            ObjTrackState *pNode = device_data->object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)];
-            if ((begin_info->pInheritanceInfo) && (pNode->status & OBJSTATUS_COMMAND_BUFFER_SECONDARY) &&
-                (begin_info->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
-                skip |=
-                    ValidateObject(command_buffer, begin_info->pInheritanceInfo->framebuffer, kVulkanObjectTypeFramebuffer, true,
+    skip |= ValidateObject(command_buffer, command_buffer, kVulkanObjectTypeCommandBuffer, false,
+                           "VUID-vkBeginCommandBuffer-commandBuffer-parameter", kVUIDUndefined);
+    if (begin_info) {
+        ObjTrackState *pNode = object_map[kVulkanObjectTypeCommandBuffer][HandleToUint64(command_buffer)];
+        if ((begin_info->pInheritanceInfo) && (pNode->status & OBJSTATUS_COMMAND_BUFFER_SECONDARY) &&
+            (begin_info->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
+            skip |= ValidateObject(command_buffer, begin_info->pInheritanceInfo->framebuffer, kVulkanObjectTypeFramebuffer, true,
                                    "VUID-VkCommandBufferBeginInfo-flags-00055", "VUID-VkCommandBufferInheritanceInfo-commonparent");
-                skip |=
-                    ValidateObject(command_buffer, begin_info->pInheritanceInfo->renderPass, kVulkanObjectTypeRenderPass, false,
+            skip |= ValidateObject(command_buffer, begin_info->pInheritanceInfo->renderPass, kVulkanObjectTypeRenderPass, false,
                                    "VUID-VkCommandBufferBeginInfo-flags-00053", "VUID-VkCommandBufferInheritanceInfo-commonparent");
-            }
         }
     }
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    VkResult result = device_data->device_dispatch_table.BeginCommandBuffer(command_buffer, begin_info);
-    return result;
+    return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
-                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugReportCallbackEXT *pCallback) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
-    if (VK_SUCCESS == result) {
-        result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
-        CreateObject(instance, *pCallback, kVulkanObjectTypeDebugReportCallbackEXT, pAllocator);
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    instance_data->instance_dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-    layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
-    DestroyObject(instance, msgCallback, kVulkanObjectTypeDebugReportCallbackEXT, pAllocator,
-                  "VUID-vkDestroyDebugReportCallbackEXT-instance-01242", "VUID-vkDestroyDebugReportCallbackEXT-instance-01243");
-}
-
-VKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    instance_data->instance_dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
-                                                                 pMsg);
-}
-
-// VK_EXT_debug_utils commands
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (pNameInfo->pObjectName) {
-        lock.lock();
-        dev_data->report_data->debugUtilsObjectNameMap->insert(
-            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->objectHandle, pNameInfo->pObjectName));
-        lock.unlock();
-    } else {
-        lock.lock();
-        dev_data->report_data->debugUtilsObjectNameMap->erase(pNameInfo->objectHandle);
-        lock.unlock();
-    }
-    VkResult result = dev_data->device_dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo);
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->device_dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo);
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL QueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    if (!skip) {
-        lock.lock();
-        BeginQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
-        lock.unlock();
-        dev_data->device_dispatch_table.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL QueueEndDebugUtilsLabelEXT(VkQueue queue) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    if (!skip) {
-        dev_data->device_dispatch_table.QueueEndDebugUtilsLabelEXT(queue);
-        lock.lock();
-        EndQueueDebugUtilsLabel(dev_data->report_data, queue);
-        lock.unlock();
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL QueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    if (!skip) {
-        lock.lock();
-        InsertQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
-        lock.unlock();
-        dev_data->device_dispatch_table.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    if (!skip) {
-        lock.lock();
-        BeginCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
-        lock.unlock();
-        dev_data->device_dispatch_table.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    if (!skip) {
-        dev_data->device_dispatch_table.CmdEndDebugUtilsLabelEXT(commandBuffer);
-        lock.lock();
-        EndCmdDebugUtilsLabel(dev_data->report_data, commandBuffer);
-        lock.unlock();
-    }
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, kVUIDUndefined, kVUIDUndefined);
-    lock.unlock();
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    if (!skip) {
-        lock.lock();
-        InsertCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
-        lock.unlock();
-        dev_data->device_dispatch_table.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugUtilsMessengerEXT *pMessenger) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-    if (VK_SUCCESS == result) {
-        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
-        CreateObject(instance, *pMessenger, kVulkanObjectTypeDebugUtilsMessengerEXT, pAllocator);
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    instance_data->instance_dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-    layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-    DestroyObject(instance, messenger, kVulkanObjectTypeDebugUtilsMessengerEXT, pAllocator, kVUIDUndefined, kVUIDUndefined);
-}
-
-VKAPI_ATTR void VKAPI_CALL SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-                                                      VkDebugUtilsMessageTypeFlagsEXT messageTypes,
-                                                      const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    instance_data->instance_dispatch_table.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
-}
-
-static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
-                                                            {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
-
-static const VkLayerProperties globalLayerProps = {"VK_LAYER_LUNARG_object_tracker",
-                                                   VK_LAYER_API_VERSION,  // specVersion
-                                                   1,                     // implementationVersion
-                                                   "LunarG Validation Layer"};
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                              VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                    VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))
-        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
-
-    return VK_ERROR_LAYER_NOT_PRESENT;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
-                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))
-        return util_GetExtensionProperties(0, nullptr, pCount, pProperties);
-
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    return instance_data->instance_dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
-                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
-    std::lock_guard<std::mutex> lock(global_lock);
-    bool skip = ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
-                               "VUID-vkCreateDevice-physicalDevice-parameter", kVUIDUndefined);
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    layer_data *phy_dev_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
-    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(phy_dev_data->instance, "vkCreateDevice");
-    if (fpCreateDevice == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-    device_data->report_data = layer_debug_utils_create_device(phy_dev_data->report_data, *pDevice);
-    layer_init_device_dispatch_table(*pDevice, &device_data->device_dispatch_table, fpGetDeviceProcAddr);
-
-    // Save pCreateInfo device extension list for GetDeviceProcAddr()
-    for (uint32_t extn = 0; extn < pCreateInfo->enabledExtensionCount; extn++) {
-        device_data->device_extension_set.insert(pCreateInfo->ppEnabledExtensionNames[extn]);
-    }
-
-    // Add link back to physDev
-    device_data->physical_device = physicalDevice;
-    device_data->instance = phy_dev_data->instance;
-
-    CreateObject(phy_dev_data->instance, *pDevice, kVulkanObjectTypeDevice, pAllocator);
-
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
-                                                     VkImage *pSwapchainImages) {
+bool ObjectLifetimes::PreCallValidateGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain,
+                                                           uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkGetSwapchainImagesKHR-device-parameter",
-                           kVUIDUndefined);
+                           "VUID-vkGetSwapchainImagesKHR-commonparent");
     skip |= ValidateObject(device, swapchain, kVulkanObjectTypeSwapchainKHR, false,
-                           "VUID-vkGetSwapchainImagesKHR-swapchain-parameter", kVUIDUndefined);
-    lock.unlock();
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+                           "VUID-vkGetSwapchainImagesKHR-swapchain-parameter", "VUID-vkGetSwapchainImagesKHR-commonparent");
+    return skip;
+}
 
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result =
-        device_data->device_dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+void ObjectLifetimes::PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                          VkImage *pSwapchainImages, VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
     if (pSwapchainImages != NULL) {
-        lock.lock();
         for (uint32_t i = 0; i < *pSwapchainImageCount; i++) {
             CreateSwapchainImageObject(device, pSwapchainImages[i], swapchain);
         }
-        lock.unlock();
     }
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
-                                                         const VkAllocationCallbacks *pAllocator,
-                                                         VkDescriptorSetLayout *pSetLayout) {
+bool ObjectLifetimes::PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                               const VkAllocationCallbacks *pAllocator,
+                                                               VkDescriptorSetLayout *pSetLayout) {
     bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkCreateDescriptorSetLayout-device-parameter",
-                               kVUIDUndefined);
-        if (pCreateInfo) {
-            if (pCreateInfo->pBindings) {
-                for (uint32_t binding_index = 0; binding_index < pCreateInfo->bindingCount; ++binding_index) {
-                    const VkDescriptorSetLayoutBinding &binding = pCreateInfo->pBindings[binding_index];
-                    const bool is_sampler_type = binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
-                                                 binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-                    if (binding.pImmutableSamplers && is_sampler_type) {
-                        for (uint32_t index2 = 0; index2 < binding.descriptorCount; ++index2) {
-                            const VkSampler sampler = binding.pImmutableSamplers[index2];
-                            skip |= ValidateObject(device, sampler, kVulkanObjectTypeSampler, false,
-                                                   "VUID-VkDescriptorSetLayoutBinding-descriptorType-00282", kVUIDUndefined);
-                        }
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkCreateDescriptorSetLayout-device-parameter",
+                           kVUIDUndefined);
+    if (pCreateInfo) {
+        if (pCreateInfo->pBindings) {
+            for (uint32_t binding_index = 0; binding_index < pCreateInfo->bindingCount; ++binding_index) {
+                const VkDescriptorSetLayoutBinding &binding = pCreateInfo->pBindings[binding_index];
+                const bool is_sampler_type = binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
+                                             binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+                if (binding.pImmutableSamplers && is_sampler_type) {
+                    for (uint32_t index2 = 0; index2 < binding.descriptorCount; ++index2) {
+                        const VkSampler sampler = binding.pImmutableSamplers[index2];
+                        skip |= ValidateObject(device, sampler, kVulkanObjectTypeSampler, false,
+                                               "VUID-VkDescriptorSetLayoutBinding-descriptorType-00282", kVUIDUndefined);
                     }
                 }
             }
         }
     }
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = device_data->device_dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        CreateObject(device, *pSetLayout, kVulkanObjectTypeDescriptorSetLayout, pAllocator);
-    }
-    return result;
+    return skip;
 }
 
-static inline bool ValidateSamplerObjects(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo) {
+void ObjectLifetimes::PostCallRecordCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                              const VkAllocationCallbacks *pAllocator,
+                                                              VkDescriptorSetLayout *pSetLayout, VkResult result) {
+    if (result != VK_SUCCESS) return;
+    CreateObject(device, *pSetLayout, kVulkanObjectTypeDescriptorSetLayout, pAllocator);
+}
+
+bool ObjectLifetimes::ValidateSamplerObjects(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo) {
     bool skip = false;
     if (pCreateInfo->pBindings) {
         for (uint32_t index1 = 0; index1 < pCreateInfo->bindingCount; ++index1) {
@@ -932,160 +564,74 @@
     return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
-                                                         VkDescriptorSetLayoutSupport *pSupport) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false,
+bool ObjectLifetimes::PreCallValidateGetDescriptorSetLayoutSupport(VkDevice device,
+                                                                   const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                                   VkDescriptorSetLayoutSupport *pSupport) {
+    bool skip = ValidateObject(device, device, kVulkanObjectTypeDevice, false,
                                "VUID-vkGetDescriptorSetLayoutSupport-device-parameter", kVUIDUndefined);
-        if (pCreateInfo) {
-            skip |= ValidateSamplerObjects(device, pCreateInfo);
-        }
+    if (pCreateInfo) {
+        skip |= ValidateSamplerObjects(device, pCreateInfo);
     }
-    if (skip) return;
-    GetLayerDataPtr(get_dispatch_key(device), layer_data_map)
-        ->device_dispatch_table.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+    return skip;
 }
-
-VKAPI_ATTR void VKAPI_CALL GetDescriptorSetLayoutSupportKHR(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
-                                                            VkDescriptorSetLayoutSupport *pSupport) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false,
+bool ObjectLifetimes::PreCallValidateGetDescriptorSetLayoutSupportKHR(VkDevice device,
+                                                                      const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                                      VkDescriptorSetLayoutSupport *pSupport) {
+    bool skip = ValidateObject(device, device, kVulkanObjectTypeDevice, false,
                                "VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter", kVUIDUndefined);
-        if (pCreateInfo) {
-            skip |= ValidateSamplerObjects(device, pCreateInfo);
-        }
+    if (pCreateInfo) {
+        skip |= ValidateSamplerObjects(device, pCreateInfo);
     }
-    if (skip) return;
-    GetLayerDataPtr(get_dispatch_key(device), layer_data_map)
-        ->device_dispatch_table.GetDescriptorSetLayoutSupportKHR(device, pCreateInfo, pSupport);
+    return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
-                                                                  uint32_t *pQueueFamilyPropertyCount,
-                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
-                               "VUID-vkGetPhysicalDeviceQueueFamilyProperties-physicalDevice-parameter", kVUIDUndefined);
-    }
-    if (skip) {
-        return;
-    }
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    instance_data->instance_dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
-                                                                                  pQueueFamilyProperties);
-    std::lock_guard<std::mutex> lock(global_lock);
+bool ObjectLifetimes::PreCallValidateGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
+                                                                            uint32_t *pQueueFamilyPropertyCount,
+                                                                            VkQueueFamilyProperties *pQueueFamilyProperties) {
+    return ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                          "VUID-vkGetPhysicalDeviceQueueFamilyProperties-physicalDevice-parameter", kVUIDUndefined);
+}
+
+void ObjectLifetimes::PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t *pQueueFamilyPropertyCount,
+                                                                           VkQueueFamilyProperties *pQueueFamilyProperties) {
     if (pQueueFamilyProperties != NULL) {
-        if (instance_data->queue_family_properties.size() < *pQueueFamilyPropertyCount) {
-            instance_data->queue_family_properties.resize(*pQueueFamilyPropertyCount);
+        if (queue_family_properties.size() < *pQueueFamilyPropertyCount) {
+            queue_family_properties.resize(*pQueueFamilyPropertyCount);
         }
         for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; i++) {
-            instance_data->queue_family_properties[i] = pQueueFamilyProperties[i];
+            queue_family_properties[i] = pQueueFamilyProperties[i];
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                                              VkInstance *pInstance) {
-    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
-    if (fpCreateInstance == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
-    instance_data->instance = *pInstance;
-    layer_init_instance_dispatch_table(*pInstance, &instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
-
-    // Look for one or more debug report create info structures, and copy the
-    // callback(s) for each one found (for use by vkDestroyInstance)
-    layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &instance_data->num_tmp_debug_messengers,
-                                    &instance_data->tmp_messenger_create_infos, &instance_data->tmp_debug_messengers);
-    layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_report_callbacks,
-                                    &instance_data->tmp_report_create_infos, &instance_data->tmp_report_callbacks);
-
-    instance_data->report_data =
-        debug_utils_create_instance(&instance_data->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
-                                    pCreateInfo->ppEnabledExtensionNames);
-
-    InitObjectTracker(instance_data, pAllocator);
-
+void ObjectLifetimes::PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
+                                                   VkInstance *pInstance, VkResult result) {
+    if (result != VK_SUCCESS) return;
     CreateObject(*pInstance, *pInstance, kVulkanObjectTypeInstance, pAllocator);
-
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
-                                                        VkPhysicalDevice *pPhysicalDevices) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(instance, instance, kVulkanObjectTypeInstance, false,
-                           "VUID-vkEnumeratePhysicalDevices-instance-parameter", kVUIDUndefined);
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
-    lock.lock();
-    if (result == VK_SUCCESS) {
-        if (pPhysicalDevices) {
-            for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
-                CreateObject(instance, pPhysicalDevices[i], kVulkanObjectTypePhysicalDevice, nullptr);
-            }
-        }
-    }
-    lock.unlock();
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
-                                                      VkCommandBuffer *pCommandBuffers) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
+bool ObjectLifetimes::PreCallValidateAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
+                                                            VkCommandBuffer *pCommandBuffers) {
+    bool skip = false;
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkAllocateCommandBuffers-device-parameter",
                            kVUIDUndefined);
     skip |= ValidateObject(device, pAllocateInfo->commandPool, kVulkanObjectTypeCommandPool, false,
                            "VUID-VkCommandBufferAllocateInfo-commandPool-parameter", kVUIDUndefined);
-    lock.unlock();
+    return skip;
+}
 
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = device_data->device_dispatch_table.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
-
-    lock.lock();
+void ObjectLifetimes::PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
+                                                           VkCommandBuffer *pCommandBuffers, VkResult result) {
+    if (result != VK_SUCCESS) return;
     for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
         AllocateCommandBuffer(device, pAllocateInfo->commandPool, pCommandBuffers[i], pAllocateInfo->level);
     }
-    lock.unlock();
-
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
-                                                      VkDescriptorSet *pDescriptorSets) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
+bool ObjectLifetimes::PreCallValidateAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                            VkDescriptorSet *pDescriptorSets) {
+    bool skip = false;
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkAllocateDescriptorSets-device-parameter",
                            kVUIDUndefined);
     skip |= ValidateObject(device, pAllocateInfo->descriptorPool, kVulkanObjectTypeDescriptorPool, false,
@@ -1096,77 +642,66 @@
                                "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-parameter",
                                "VUID-VkDescriptorSetAllocateInfo-commonparent");
     }
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = device_data->device_dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
-
-    if (VK_SUCCESS == result) {
-        lock.lock();
-        for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
-            AllocateDescriptorSet(device, pAllocateInfo->descriptorPool, pDescriptorSets[i]);
-        }
-        lock.unlock();
-    }
-
-    return result;
+    return skip;
 }
 
-VKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
-                                              const VkCommandBuffer *pCommandBuffers) {
+void ObjectLifetimes::PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                           VkDescriptorSet *pDescriptorSets, VkResult result) {
+    if (result != VK_SUCCESS) return;
+    for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
+        AllocateDescriptorSet(device, pAllocateInfo->descriptorPool, pDescriptorSets[i]);
+    }
+}
+
+bool ObjectLifetimes::PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                        const VkCommandBuffer *pCommandBuffers) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
-    ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkFreeCommandBuffers-device-parameter", kVUIDUndefined);
-    ValidateObject(device, commandPool, kVulkanObjectTypeCommandPool, false, "VUID-vkFreeCommandBuffers-commandPool-parameter",
-                   "VUID-vkFreeCommandBuffers-commandPool-parent");
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkFreeCommandBuffers-device-parameter",
+                           kVUIDUndefined);
+    skip |= ValidateObject(device, commandPool, kVulkanObjectTypeCommandPool, false,
+                           "VUID-vkFreeCommandBuffers-commandPool-parameter", "VUID-vkFreeCommandBuffers-commandPool-parent");
     for (uint32_t i = 0; i < commandBufferCount; i++) {
         if (pCommandBuffers[i] != VK_NULL_HANDLE) {
             skip |= ValidateCommandBuffer(device, commandPool, pCommandBuffers[i]);
+            skip |= ValidateDestroyObject(device, pCommandBuffers[i], kVulkanObjectTypeCommandBuffer, nullptr, kVUIDUndefined,
+                                          kVUIDUndefined);
         }
     }
+    return skip;
+}
 
+void ObjectLifetimes::PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                      const VkCommandBuffer *pCommandBuffers) {
     for (uint32_t i = 0; i < commandBufferCount; i++) {
-        DestroyObject(device, pCommandBuffers[i], kVulkanObjectTypeCommandBuffer, nullptr, kVUIDUndefined, kVUIDUndefined);
-    }
-
-    lock.unlock();
-    if (!skip) {
-        layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-        device_data->device_dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
+        RecordDestroyObject(device, pCommandBuffers[i], kVulkanObjectTypeCommandBuffer);
     }
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    // A swapchain's images are implicitly deleted when the swapchain is deleted.
-    // Remove this swapchain's images from our map of such images.
-    std::unordered_map<uint64_t, ObjTrackState *>::iterator itr = device_data->swapchainImageMap.begin();
-    while (itr != device_data->swapchainImageMap.end()) {
+bool ObjectLifetimes::PreCallValidateDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    return ValidateDestroyObject(device, swapchain, kVulkanObjectTypeSwapchainKHR, pAllocator,
+                                 "VUID-vkDestroySwapchainKHR-swapchain-01283", "VUID-vkDestroySwapchainKHR-swapchain-01284");
+}
+
+void ObjectLifetimes::PreCallRecordDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
+                                                       const VkAllocationCallbacks *pAllocator) {
+    RecordDestroyObject(device, swapchain, kVulkanObjectTypeSwapchainKHR);
+    std::unordered_map<uint64_t, ObjTrackState *>::iterator itr = swapchainImageMap.begin();
+    while (itr != swapchainImageMap.end()) {
         ObjTrackState *pNode = (*itr).second;
         if (pNode->parent_object == HandleToUint64(swapchain)) {
             delete pNode;
             auto delete_item = itr++;
-            device_data->swapchainImageMap.erase(delete_item);
+            swapchainImageMap.erase(delete_item);
         } else {
             ++itr;
         }
     }
-    DestroyObject(device, swapchain, kVulkanObjectTypeSwapchainKHR, pAllocator, "VUID-vkDestroySwapchainKHR-swapchain-01283",
-                  "VUID-vkDestroySwapchainKHR-swapchain-01284");
-    lock.unlock();
-
-    device_data->device_dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
-                                                  const VkDescriptorSet *pDescriptorSets) {
+bool ObjectLifetimes::PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool,
+                                                        uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) {
     bool skip = false;
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::unique_lock<std::mutex> lock(global_lock);
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkFreeDescriptorSets-device-parameter",
                            kVUIDUndefined);
     skip |= ValidateObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool, false,
@@ -1174,370 +709,213 @@
     for (uint32_t i = 0; i < descriptorSetCount; i++) {
         if (pDescriptorSets[i] != VK_NULL_HANDLE) {
             skip |= ValidateDescriptorSet(device, descriptorPool, pDescriptorSets[i]);
+            skip |= ValidateDestroyObject(device, pDescriptorSets[i], kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined,
+                                          kVUIDUndefined);
         }
     }
-
+    return skip;
+}
+void ObjectLifetimes::PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
+                                                      const VkDescriptorSet *pDescriptorSets) {
+    ObjTrackState *pPoolNode = nullptr;
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptorPool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        pPoolNode = itr->second;
+    }
     for (uint32_t i = 0; i < descriptorSetCount; i++) {
-        DestroyObject(device, pDescriptorSets[i], kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined, kVUIDUndefined);
+        RecordDestroyObject(device, pDescriptorSets[i], kVulkanObjectTypeDescriptorSet);
+        if (pPoolNode) {
+            pPoolNode->child_objects->erase(HandleToUint64(pDescriptorSets[i]));
+        }
     }
-
-    lock.unlock();
-    if (!skip) {
-        layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-        result = device_data->device_dispatch_table.FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets);
-    }
-    return result;
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
-                                                 const VkAllocationCallbacks *pAllocator) {
-    bool skip = VK_FALSE;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
+bool ObjectLifetimes::PreCallValidateDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                           const VkAllocationCallbacks *pAllocator) {
+    bool skip = false;
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkDestroyDescriptorPool-device-parameter",
                            kVUIDUndefined);
     skip |= ValidateObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool, true,
                            "VUID-vkDestroyDescriptorPool-descriptorPool-parameter",
                            "VUID-vkDestroyDescriptorPool-descriptorPool-parent");
-    lock.unlock();
-    if (skip) {
-        return;
-    }
-    // A DescriptorPool's descriptor sets are implicitly deleted when the pool is deleted.
-    // Remove this pool's descriptor sets from our descriptorSet map.
-    lock.lock();
-    std::unordered_map<uint64_t, ObjTrackState *>::iterator itr = device_data->object_map[kVulkanObjectTypeDescriptorSet].begin();
-    while (itr != device_data->object_map[kVulkanObjectTypeDescriptorSet].end()) {
-        ObjTrackState *pNode = (*itr).second;
-        auto del_itr = itr++;
-        if (pNode->parent_object == HandleToUint64(descriptorPool)) {
-            DestroyObject(device, (VkDescriptorSet)((*del_itr).first), kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined,
-                          kVUIDUndefined);
+
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptorPool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        ObjTrackState *pPoolNode = itr->second;
+        for (auto set : *pPoolNode->child_objects) {
+            skip |= ValidateDestroyObject(device, (VkDescriptorSet)set, kVulkanObjectTypeDescriptorSet, nullptr, kVUIDUndefined,
+                                          kVUIDUndefined);
         }
     }
-    DestroyObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool, pAllocator,
-                  "VUID-vkDestroyDescriptorPool-descriptorPool-00304", "VUID-vkDestroyDescriptorPool-descriptorPool-00305");
-    lock.unlock();
-    device_data->device_dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
+    skip |= ValidateDestroyObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool, pAllocator,
+                                  "VUID-vkDestroyDescriptorPool-descriptorPool-00304",
+                                  "VUID-vkDestroyDescriptorPool-descriptorPool-00305");
+    return skip;
+}
+void ObjectLifetimes::PreCallRecordDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    auto itr = object_map[kVulkanObjectTypeDescriptorPool].find(HandleToUint64(descriptorPool));
+    if (itr != object_map[kVulkanObjectTypeDescriptorPool].end()) {
+        ObjTrackState *pPoolNode = itr->second;
+        for (auto set : *pPoolNode->child_objects) {
+            RecordDestroyObject(device, (VkDescriptorSet)set, kVulkanObjectTypeDescriptorSet);
+        }
+        pPoolNode->child_objects->clear();
+    }
+    RecordDestroyObject(device, descriptorPool, kVulkanObjectTypeDescriptorPool);
 }
 
-VKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool ObjectLifetimes::PreCallValidateDestroyCommandPool(VkDevice device, VkCommandPool commandPool,
+                                                        const VkAllocationCallbacks *pAllocator) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
     skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkDestroyCommandPool-device-parameter",
                            kVUIDUndefined);
     skip |= ValidateObject(device, commandPool, kVulkanObjectTypeCommandPool, true,
                            "VUID-vkDestroyCommandPool-commandPool-parameter", "VUID-vkDestroyCommandPool-commandPool-parent");
-    lock.unlock();
-    if (skip) {
-        return;
-    }
-    lock.lock();
-    // A CommandPool's command buffers are implicitly deleted when the pool is deleted.
-    // Remove this pool's cmdBuffers from our cmd buffer map.
-    auto itr = device_data->object_map[kVulkanObjectTypeCommandBuffer].begin();
+    auto itr = object_map[kVulkanObjectTypeCommandBuffer].begin();
     auto del_itr = itr;
-    while (itr != device_data->object_map[kVulkanObjectTypeCommandBuffer].end()) {
+    while (itr != object_map[kVulkanObjectTypeCommandBuffer].end()) {
         ObjTrackState *pNode = (*itr).second;
         del_itr = itr++;
         if (pNode->parent_object == HandleToUint64(commandPool)) {
             skip |= ValidateCommandBuffer(device, commandPool, reinterpret_cast<VkCommandBuffer>((*del_itr).first));
-            DestroyObject(device, reinterpret_cast<VkCommandBuffer>((*del_itr).first), kVulkanObjectTypeCommandBuffer, nullptr,
-                          kVUIDUndefined, kVUIDUndefined);
+            skip |= ValidateDestroyObject(device, reinterpret_cast<VkCommandBuffer>((*del_itr).first),
+                                          kVulkanObjectTypeCommandBuffer, nullptr, kVUIDUndefined, kVUIDUndefined);
         }
     }
-    DestroyObject(device, commandPool, kVulkanObjectTypeCommandPool, pAllocator, "VUID-vkDestroyCommandPool-commandPool-00042",
-                  "VUID-vkDestroyCommandPool-commandPool-00043");
-    lock.unlock();
-    device_data->device_dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
+    skip |= ValidateDestroyObject(device, commandPool, kVulkanObjectTypeCommandPool, pAllocator,
+                                  "VUID-vkDestroyCommandPool-commandPool-00042", "VUID-vkDestroyCommandPool-commandPool-00043");
+    return skip;
 }
 
-// Note: This is the core version of this routine.  The extension version is below.
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
-                                                                   uint32_t *pQueueFamilyPropertyCount,
-                                                                   VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |=
-            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
+void ObjectLifetimes::PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool,
+                                                      const VkAllocationCallbacks *pAllocator) {
+    auto itr = object_map[kVulkanObjectTypeCommandBuffer].begin();
+    auto del_itr = itr;
+    // A CommandPool's cmd buffers are implicitly deleted when pool is deleted. Remove this pool's cmdBuffers from cmd buffer map.
+    while (itr != object_map[kVulkanObjectTypeCommandBuffer].end()) {
+        ObjTrackState *pNode = (*itr).second;
+        del_itr = itr++;
+        if (pNode->parent_object == HandleToUint64(commandPool)) {
+            RecordDestroyObject(device, reinterpret_cast<VkCommandBuffer>((*del_itr).first), kVulkanObjectTypeCommandBuffer);
+        }
     }
-    if (skip) {
-        return;
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    instance_data->instance_dispatch_table.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount,
-                                                                                   pQueueFamilyProperties);
-    std::lock_guard<std::mutex> lock(global_lock);
+    RecordDestroyObject(device, commandPool, kVulkanObjectTypeCommandPool);
+}
+
+bool ObjectLifetimes::PreCallValidateGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
+                                                                             uint32_t *pQueueFamilyPropertyCount,
+                                                                             VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
+    return ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                          "VUID-vkGetPhysicalDeviceQueueFamilyProperties2-physicalDevice-parameter", kVUIDUndefined);
+}
+
+bool ObjectLifetimes::PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                                uint32_t *pQueueFamilyPropertyCount,
+                                                                                VkQueueFamilyProperties2 *pQueueFamilyProperties) {
+    return ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                          "VUID-vkGetPhysicalDeviceQueueFamilyProperties2-physicalDevice-parameter", kVUIDUndefined);
+}
+
+void ObjectLifetimes::PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
+                                                                            uint32_t *pQueueFamilyPropertyCount,
+                                                                            VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
     if (pQueueFamilyProperties != NULL) {
-        if (instance_data->queue_family_properties.size() < *pQueueFamilyPropertyCount) {
-            instance_data->queue_family_properties.resize(*pQueueFamilyPropertyCount);
+        if (queue_family_properties.size() < *pQueueFamilyPropertyCount) {
+            queue_family_properties.resize(*pQueueFamilyPropertyCount);
         }
         for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; i++) {
-            instance_data->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
+            queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
         }
     }
 }
 
-// Note: This is the extension version of this routine.  The core version is above.
-VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
-                                                                      uint32_t *pQueueFamilyPropertyCount,
-                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |=
-            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
-    }
-    if (skip) {
-        return;
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    instance_data->instance_dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
-                                                                                      pQueueFamilyProperties);
-    std::lock_guard<std::mutex> lock(global_lock);
+void ObjectLifetimes::PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
     if (pQueueFamilyProperties != NULL) {
-        if (instance_data->queue_family_properties.size() < *pQueueFamilyPropertyCount) {
-            instance_data->queue_family_properties.resize(*pQueueFamilyPropertyCount);
+        if (queue_family_properties.size() < *pQueueFamilyPropertyCount) {
+            queue_family_properties.resize(*pQueueFamilyPropertyCount);
         }
         for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; i++) {
-            instance_data->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
+            queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
         }
     }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                     VkDisplayPropertiesKHR *pProperties) {
-    bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
-    skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
-                           "VUID-vkGetPhysicalDeviceDisplayPropertiesKHR-physicalDevice-parameter", kVUIDUndefined);
-    lock.unlock();
+bool ObjectLifetimes::PreCallValidateGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t *pPropertyCount,
+                                                                           VkDisplayPropertiesKHR *pProperties) {
+    return ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                          "VUID-vkGetPhysicalDeviceDisplayPropertiesKHR-physicalDevice-parameter", kVUIDUndefined);
+}
 
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, pProperties);
-
-    lock.lock();
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+void ObjectLifetimes::PostCallRecordGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                                          VkDisplayPropertiesKHR *pProperties, VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    if (pProperties) {
         for (uint32_t i = 0; i < *pPropertyCount; ++i) {
             CreateObject(physicalDevice, pProperties[i].display, kVulkanObjectTypeDisplayKHR, nullptr);
         }
     }
-    lock.unlock();
-
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
-                                                           uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties) {
+bool ObjectLifetimes::PreCallValidateGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                                 uint32_t *pPropertyCount,
+                                                                 VkDisplayModePropertiesKHR *pProperties) {
     bool skip = false;
-    std::unique_lock<std::mutex> lock(global_lock);
     skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
                            "VUID-vkGetDisplayModePropertiesKHR-physicalDevice-parameter", kVUIDUndefined);
     skip |= ValidateObject(physicalDevice, display, kVulkanObjectTypeDisplayKHR, false,
                            "VUID-vkGetDisplayModePropertiesKHR-display-parameter", kVUIDUndefined);
-    lock.unlock();
 
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties);
+    return skip;
+}
 
-    lock.lock();
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+void ObjectLifetimes::PostCallRecordGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                                uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties,
+                                                                VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    if (pProperties) {
         for (uint32_t i = 0; i < *pPropertyCount; ++i) {
             CreateObject(physicalDevice, pProperties[i].displayMode, kVulkanObjectTypeDisplayModeKHR, nullptr);
         }
     }
-
-    lock.unlock();
-
-    return result;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
-    bool skip = VK_FALSE;
-    std::unique_lock<std::mutex> lock(global_lock);
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (pNameInfo->pObjectName) {
-        dev_data->report_data->debugObjectNameMap->insert(
-            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->object, pNameInfo->pObjectName));
-    } else {
-        dev_data->report_data->debugObjectNameMap->erase(pNameInfo->object);
-    }
-    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, "VUID-vkDebugMarkerSetObjectNameEXT-device-parameter",
-                           kVUIDUndefined);
-    lock.unlock();
-    if (skip) {
-        return VK_ERROR_VALIDATION_FAILED_EXT;
-    }
-    VkResult result = dev_data->device_dispatch_table.DebugMarkerSetObjectNameEXT(device, pNameInfo);
-    return result;
+bool ObjectLifetimes::PreCallValidateGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                            uint32_t *pPropertyCount,
+                                                                            VkDisplayProperties2KHR *pProperties) {
+    return ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                          "VUID-vkGetPhysicalDeviceDisplayProperties2KHR-physicalDevice-parameter", kVUIDUndefined);
 }
 
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
-    assert(instance);
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    if (instance_data->instance_dispatch_table.GetPhysicalDeviceProcAddr == NULL) {
-        return NULL;
+void ObjectLifetimes::PostCallRecordGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice,
+                                                                           uint32_t *pPropertyCount,
+                                                                           VkDisplayProperties2KHR *pProperties, VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    for (uint32_t index = 0; index < *pPropertyCount; ++index) {
+        CreateObject(physicalDevice, pProperties[index].displayProperties.display, kVulkanObjectTypeDisplayKHR, nullptr);
     }
-    return instance_data->instance_dispatch_table.GetPhysicalDeviceProcAddr(instance, funcName);
 }
 
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (!ApiParentExtensionEnabled(funcName, device_data->device_extension_set)) {
-        return nullptr;
-    }
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-    if (!device_data->device_dispatch_table.GetDeviceProcAddr) return NULL;
-    return device_data->device_dispatch_table.GetDeviceProcAddr(device, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    if (!instance_data->instance_dispatch_table.GetInstanceProcAddr) return nullptr;
-    return instance_data->instance_dispatch_table.GetInstanceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                      VkDisplayProperties2KHR *pProperties) {
+bool ObjectLifetimes::PreCallValidateGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                                  uint32_t *pPropertyCount,
+                                                                  VkDisplayModeProperties2KHR *pProperties) {
     bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |=
-            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
+    skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
+                           "VUID-vkGetDisplayModeProperties2KHR-physicalDevice-parameter", kVUIDUndefined);
+    skip |= ValidateObject(physicalDevice, display, kVulkanObjectTypeDisplayKHR, false,
+                           "VUID-vkGetDisplayModeProperties2KHR-display-parameter", kVUIDUndefined);
+
+    return skip;
+}
+
+void ObjectLifetimes::PostCallRecordGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                                 uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties,
+                                                                 VkResult result) {
+    if ((result != VK_SUCCESS) && (result != VK_INCOMPLETE)) return;
+    for (uint32_t index = 0; index < *pPropertyCount; ++index) {
+        CreateObject(physicalDevice, pProperties[index].displayModeProperties.displayMode, kVulkanObjectTypeDisplayModeKHR,
+                     nullptr);
     }
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, pPropertyCount, pProperties);
-    if (pProperties && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t index = 0; index < *pPropertyCount; ++index) {
-            CreateObject(physicalDevice, pProperties[index].displayProperties.display, kVulkanObjectTypeDisplayKHR, nullptr);
-        }
-    }
-
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
-                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |= ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false,
-                               "VUID-vkGetDisplayPlaneSupportedDisplaysKHR-physicalDevice-parameter", kVUIDUndefined);
-    }
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result = instance_data->instance_dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex,
-                                                                                                 pDisplayCount, pDisplays);
-    if (pDisplays && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t index = 0; index < *pDisplayCount; ++index) {
-            CreateObject(physicalDevice, pDisplays[index], kVulkanObjectTypeDisplayKHR, nullptr);
-        }
-    }
-
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
-                                                            uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties) {
-    bool skip = false;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        skip |=
-            ValidateObject(physicalDevice, physicalDevice, kVulkanObjectTypePhysicalDevice, false, kVUIDUndefined, kVUIDUndefined);
-        skip |= ValidateObject(physicalDevice, display, kVulkanObjectTypeDisplayKHR, false, kVUIDUndefined, kVUIDUndefined);
-    }
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result =
-        instance_data->instance_dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties);
-    if (pProperties && (VK_SUCCESS == result || VK_INCOMPLETE == result)) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t index = 0; index < *pPropertyCount; ++index) {
-            CreateObject(physicalDevice, pProperties[index].displayModeProperties.displayMode, kVulkanObjectTypeDisplayModeKHR,
-                         nullptr);
-        }
-    }
-
-    return result;
-}
-
-}  // namespace object_tracker
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                                      VkExtensionProperties *pProperties) {
-    return object_tracker::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
-                                                                                  VkLayerProperties *pProperties) {
-    return object_tracker::EnumerateInstanceLayerProperties(pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                                VkLayerProperties *pProperties) {
-    // The layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return object_tracker::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
-    return object_tracker::GetDeviceProcAddr(dev, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    return object_tracker::GetInstanceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                                                                    const char *pLayerName, uint32_t *pCount,
-                                                                                    VkExtensionProperties *pProperties) {
-    // The layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return object_tracker::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
-                                                                                           const char *funcName) {
-    return object_tracker::GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
-    assert(pVersionStruct != NULL);
-    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
-
-    // Fill in the function pointers if our version is at least capable of having the structure contain them.
-    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
-        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
-        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
-        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
-    }
-
-    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        object_tracker::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
-    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-    }
-
-    return VK_SUCCESS;
 }
diff --git a/layers/parameter_name.h b/layers/parameter_name.h
index 05a1d89..c91f776 100644
--- a/layers/parameter_name.h
+++ b/layers/parameter_name.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2016 The Khronos Group Inc.
- * Copyright (c) 2016 Valve Corporation
- * Copyright (c) 2016 LunarG, Inc.
- * Copyright (c) 2016 Google Inc.
+/* Copyright (c) 2016-2019 The Khronos Group Inc.
+ * Copyright (c) 2016-2019 Valve Corporation
+ * Copyright (c) 2016-2019 LunarG, Inc.
+ * Copyright (c) 2016-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
  * Parameter name string supporting deferred formatting for array subscripts.
  *
  * Custom parameter name class with support for deferred formatting of names containing array subscripts.  The class stores
- * a format string and a vector of index values, and performs string formatting when an accessor function is called to
+ * a format string and a pointer to an array of index values, and performs string formatting when an accessor function is called to
  * retrieve the name string.  This class was primarily designed to be used with validation functions that receive a parameter name
  * string and value as arguments, and print an error message that includes the parameter name when the value fails a validation
  * test.  Using standard strings with these validation functions requires that parameter names containing array subscripts be
@@ -36,19 +36,22 @@
  *         sprintf(name, "pCreateInfo[%d].sType", i);
  *         validate_stype(name, pCreateInfo[i].sType);
  *
- * With the ParameterName class, a format string and a vector of format values are stored by the ParameterName object that is
- * provided to the validation function.  String formatting is then performed only when the validation function retrieves the
+ * With the ParameterName class, a format string and a pointer to an array of format values are stored by the ParameterName object
+ * that is provided to the validation function.  String formatting is then performed only when the validation function retrieves the
  * name string from the ParameterName object:
  *         validate_stype(ParameterName("pCreateInfo[%i].sType", IndexVector{ i }), pCreateInfo[i].sType);
+ *
+ * Since the IndexVector is not copied into the object, the lifetime of the ParameterName should not outlast the lifetime of
+ * the IndexVector, but that's fine given how it is used in parameter validation.
  */
 class ParameterName {
    public:
     /// Container for index values to be used with parameter name string formatting.
-    typedef std::vector<size_t> IndexVector;
+    typedef std::initializer_list<size_t> IndexVector;
 
     /// Format specifier for the parameter name string, to be replaced by an index value.  The parameter name string must contain
     /// one format specifier for each index value specified.
-    const std::string IndexFormatSpecifier = "%i";
+    const char *const IndexFormatSpecifier = "%i";
 
    public:
     /**
@@ -58,28 +61,10 @@
      *
      * @pre The source string must not contain the %i format specifier.
      */
-    ParameterName(const char *source) : source_(source) { assert(IsValid()); }
+    ParameterName(const char *source) : source_(source), num_indices_(0) { assert(IsValid()); }
 
     /**
-     * Construct a ParameterName object from a std::string object, without formatting.
-     *
-     * @param source Paramater name string without format specifiers.
-     *
-     * @pre The source string must not contain the %i format specifier.
-     */
-    ParameterName(const std::string &source) : source_(source) { assert(IsValid()); }
-
-    /**
-     * Construct a ParameterName object from a std::string object, without formatting.
-     *
-     * @param source Paramater name string without format specifiers.
-     *
-     * @pre The source string must not contain the %i format specifier.
-     */
-    ParameterName(const std::string &&source) : source_(std::move(source)) { assert(IsValid()); }
-
-    /**
-     * Construct a ParameterName object from a std::string object, with formatting.
+     * Construct a ParameterName object from a string literal, with formatting.
      *
      * @param source Paramater name string with format specifiers.
      * @param args Array index values to be used for formatting.
@@ -87,23 +72,13 @@
      * @pre The number of %i format specifiers contained by the source string must match the number of elements contained
      *      by the index vector.
      */
-    ParameterName(const std::string &source, const IndexVector &args) : source_(source), args_(args) { assert(IsValid()); }
-
-    /**
-     * Construct a ParameterName object from a std::string object, with formatting.
-     *
-     * @param source Paramater name string with format specifiers.
-     * @param args Array index values to be used for formatting.
-     *
-     * @pre The number of %i format specifiers contained by the source string must match the number of elements contained
-     *      by the index vector.
-     */
-    ParameterName(const std::string &&source, const IndexVector &&args) : source_(std::move(source)), args_(std::move(args)) {
+    ParameterName(const char *source, const IndexVector &args)
+        : source_(source), args_(args.size() ? args.begin() : (const size_t *)nullptr), num_indices_(args.size()) {
         assert(IsValid());
     }
 
     /// Retrive the formatted name string.
-    std::string get_name() const { return (args_.empty()) ? source_ : Format(); }
+    std::string get_name() const { return (num_indices_ == 0) ? std::string(source_) : Format(); }
 
    private:
     /// Replace the %i format specifiers in the source string with the values from the index vector.
@@ -112,16 +87,19 @@
         std::string::size_type last = 0;
         std::stringstream format;
 
-        for (size_t index : args_) {
-            current = source_.find(IndexFormatSpecifier, last);
+        std::string source(source_);
+
+        for (size_t i = 0; i < num_indices_; ++i) {
+            auto index = args_[i];
+            current = source.find(IndexFormatSpecifier, last);
             if (current == std::string::npos) {
                 break;
             }
-            format << source_.substr(last, (current - last)) << index;
-            last = current + IndexFormatSpecifier.length();
+            format << source.substr(last, (current - last)) << index;
+            last = current + strlen(IndexFormatSpecifier);
         }
 
-        format << source_.substr(last, std::string::npos);
+        format << source.substr(last, std::string::npos);
 
         return format.str();
     }
@@ -130,19 +108,23 @@
     bool IsValid() {
         // Count the number of occurances of the format specifier
         uint32_t count = 0;
-        std::string::size_type pos = source_.find(IndexFormatSpecifier);
+
+        std::string source(source_);
+
+        std::string::size_type pos = source.find(IndexFormatSpecifier);
 
         while (pos != std::string::npos) {
             ++count;
-            pos = source_.find(IndexFormatSpecifier, pos + 1);
+            pos = source.find(IndexFormatSpecifier, pos + 1);
         }
 
-        return (count == args_.size());
+        return (count == num_indices_);
     }
 
    private:
-    std::string source_;  ///< Format string.
-    IndexVector args_;    ///< Array index values for formatting.
+    const char *source_;  ///< Format string.
+    const size_t *args_;  ///< Array index values for formatting.
+    size_t num_indices_;  ///< Number of array index values.
 };
 
 #endif  // PARAMETER_NAME_H
diff --git a/layers/parameter_validation.h b/layers/parameter_validation.h
deleted file mode 100644
index 03643be..0000000
--- a/layers/parameter_validation.h
+++ /dev/null
@@ -1,971 +0,0 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Author: Dustin Graves <dustin@lunarg.com>
- */
-
-#ifndef PARAMETER_VALIDATION_UTILS_H
-#define PARAMETER_VALIDATION_UTILS_H
-
-#include <algorithm>
-#include <cstdlib>
-#include <string>
-#include <sstream>
-#include <bitset>
-#include <mutex>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "vulkan/vulkan.h"
-#include "vk_enum_string_helper.h"
-#include "vk_layer_logging.h"
-#include "vk_extension_helper.h"
-#include "vk_layer_utils.h"
-
-#include "parameter_name.h"
-
-namespace parameter_validation {
-
-extern const uint32_t GeneratedHeaderVersion;
-extern const std::unordered_map<std::string, void *> name_to_funcptr_map;
-
-extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
-extern const VkColorComponentFlags AllVkColorComponentFlagBits;
-extern const VkShaderStageFlags AllVkShaderStageFlagBits;
-extern const VkQueryControlFlags AllVkQueryControlFlagBits;
-extern const VkImageUsageFlags AllVkImageUsageFlagBits;
-
-extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
-extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
-extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
-extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
-extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
-extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
-extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
-
-struct instance_layer_data {
-    VkInstance instance = VK_NULL_HANDLE;
-
-    debug_report_data *report_data = nullptr;
-    std::vector<VkDebugReportCallbackEXT> logging_callback;
-    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
-
-    // The following are for keeping track of the temporary callbacks that can
-    // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_report_callbacks = 0;
-    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos = nullptr;
-    VkDebugReportCallbackEXT *tmp_report_callbacks = nullptr;
-    uint32_t num_tmp_debug_messengers = 0;
-    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos = nullptr;
-    VkDebugUtilsMessengerEXT *tmp_debug_messengers = nullptr;
-
-    InstanceExtensions extensions = {};
-    VkLayerInstanceDispatchTable dispatch_table = {};
-    uint32_t api_version;
-};
-
-struct layer_data {
-    debug_report_data *report_data = nullptr;
-    // Map for queue family index to queue count
-    std::unordered_map<uint32_t, uint32_t> queueFamilyIndexMap;
-    VkPhysicalDeviceLimits device_limits = {};
-    VkPhysicalDeviceFeatures physical_device_features = {};
-    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
-    VkDevice device = VK_NULL_HANDLE;
-    DeviceExtensions extensions;
-    uint32_t api_version;
-
-    // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain
-    struct DeviceExtensionProperties {
-        VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
-        VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
-    };
-    DeviceExtensionProperties phys_dev_ext_props = {};
-
-    struct SubpassesUsageStates {
-        std::unordered_set<uint32_t> subpasses_using_color_attachment;
-        std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
-    };
-
-    std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
-
-    VkLayerDispatchTable dispatch_table = {};
-};
-
-// Suppress unused warning on Linux
-#if defined(__GNUC__)
-#define DECORATE_UNUSED __attribute__((unused))
-#else
-#define DECORATE_UNUSED
-#endif
-
-static const char DECORATE_UNUSED *kVUID_PVError_NONE = "UNASSIGNED-GeneralParameterError-Info";
-static const char DECORATE_UNUSED *kVUID_PVError_InvalidUsage = "UNASSIGNED-GeneralParameterError-InvalidUsage";
-static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructSType = "UNASSIGNED-GeneralParameterError-InvalidStructSType";
-static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructPNext = "UNASSIGNED-GeneralParameterError-InvalidStructPNext";
-static const char DECORATE_UNUSED *kVUID_PVError_RequiredParameter = "UNASSIGNED-GeneralParameterError-RequiredParameter";
-static const char DECORATE_UNUSED *kVUID_PVError_ReservedParameter = "UNASSIGNED-GeneralParameterError-ReservedParameter";
-static const char DECORATE_UNUSED *kVUID_PVError_UnrecognizedValue = "UNASSIGNED-GeneralParameterError-UnrecognizedValue";
-static const char DECORATE_UNUSED *kVUID_PVError_DeviceLimit = "UNASSIGNED-GeneralParameterError-DeviceLimit";
-static const char DECORATE_UNUSED *kVUID_PVError_DeviceFeature = "UNASSIGNED-GeneralParameterError-DeviceFeature";
-static const char DECORATE_UNUSED *kVUID_PVError_FailureCode = "UNASSIGNED-GeneralParameterError-FailureCode";
-static const char DECORATE_UNUSED *kVUID_PVError_ExtensionNotEnabled = "UNASSIGNED-GeneralParameterError-ExtensionNotEnabled";
-
-#undef DECORATE_UNUSED
-
-#if 0  // TBD - should see if we can add the expository text below into the spec reference string database
-enum ErrorCode {
-    NONE,                   // Used for INFO & other non-error messages
-    INVALID_USAGE,          // The value of a parameter is not consistent
-                            // with the valid usage criteria defined in
-                            // the Vulkan specification.
-    INVALID_STRUCT_STYPE,   // The sType field of a Vulkan structure does
-                            // not contain the value expected for a structure
-                            // of that type.
-    INVALID_STRUCT_PNEXT,   // The pNext field of a Vulkan structure references
-                            // a value that is not compatible with a structure of
-                            // that type or is not NULL when a structure of that
-                            // type has no compatible pNext values.
-    REQUIRED_PARAMETER,     // A required parameter was specified as 0 or NULL.
-    RESERVED_PARAMETER,     // A parameter reserved for future use was not
-                            // specified as 0 or NULL.
-    UNRECOGNIZED_VALUE,     // A Vulkan enumeration, VkFlags, or VkBool32 parameter
-                            // contains a value that is not recognized as valid for
-                            // that type.
-    DEVICE_LIMIT,           // A specified parameter exceeds the limits returned
-                            // by the physical device
-    DEVICE_FEATURE,         // Use of a requested feature is not supported by
-                            // the device
-    FAILURE_RETURN_CODE,    // A Vulkan return code indicating a failure condition
-                            // was encountered.
-    EXTENSION_NOT_ENABLED,  // An extension entrypoint was called, but the required
-                            // extension was not enabled at CreateInstance or
-                            // CreateDevice time.
-};
-#endif
-
-struct GenericHeader {
-    VkStructureType sType;
-    const void *pNext;
-};
-
-// String returned by string_VkStructureType for an unrecognized type.
-const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
-
-// String returned by string_VkResult for an unrecognized type.
-const std::string UnsupportedResultString = "Unhandled VkResult";
-
-// The base value used when computing the offset for an enumeration token value that is added by an extension.
-// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
-// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
-const uint32_t ExtEnumBaseValue = 1000000000;
-
-// The value of all VK_xxx_MAX_ENUM tokens
-const uint32_t MaxEnumValue = 0x7FFFFFFF;
-
-// Misc parameters of log_msg that are likely constant per command (or low frequency change)
-struct LogMiscParams {
-    const debug_report_data *debug_data;
-    VkDebugReportObjectTypeEXT objectType;
-    uint64_t srcObject;
-    const char *api_name;
-};
-
-// Pick up VUIDS from validated substructures. Many structures contain substructures.  In addition to the implicit VUs covered
-// when each of the substructures is parsed, there is often a VUID for 'xxx MUST be a valid XxxStruct'. If all implicit valid usage
-// is covered for a substructure, we should claim the VUID for the validity of the structure itself.
-static bool ValidateSubstructure(debug_report_data *report_data, const char *api_name, const char *struct_name,
-                                 const std::string &substructure_vuid) {
-    bool skip = false;
-    if (false) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, substructure_vuid,
-                        "%s: parameter %s must be a valid structure.", api_name, struct_name);
-    }
-    return skip;
-}
-
-/**
- * Validate a minimum value.
- *
- * Verify that the specified value is greater than the specified lower bound.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param parameter_name Name of parameter being validated.
- * @param value Value to validate.
- * @param lower_bound Lower bound value to use for validation.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool ValidateGreaterThan(const T value, const T lower_bound, const ParameterName &parameter_name, const std::string &vuid,
-                         const LogMiscParams &misc) {
-    bool skip_call = false;
-
-    if (value <= lower_bound) {
-        std::ostringstream ss;
-        ss << misc.api_name << ": parameter " << parameter_name.get_name() << " (= " << value << ") is greater than "
-           << lower_bound;
-        skip_call |=
-            log_msg(misc.debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, misc.objectType, misc.srcObject, vuid, "%s", ss.str().c_str());
-    }
-
-    return skip_call;
-}
-
-template <typename T>
-bool ValidateGreaterThanZero(const T value, const ParameterName &parameter_name, const std::string &vuid,
-                             const LogMiscParams &misc) {
-    return ValidateGreaterThan(value, T{0}, parameter_name, vuid, misc);
-}
-/**
- * Validate a required pointer.
- *
- * Verify that a required pointer is not NULL.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param parameterName Name of parameter being validated.
- * @param value Pointer to validate.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_required_pointer(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
-                                      const void *value, const std::string &vuid) {
-    bool skip_call = false;
-
-    if (value == NULL) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                             "%s: required parameter %s specified as NULL.", apiName, parameterName.get_name().c_str());
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate array count and pointer to array.
- *
- * Verify that required count and array parameters are not 0 or NULL.  If the
- * count parameter is not optional, verify that it is not 0.  If the array
- * parameter is NULL, and it is not optional, verify that count is 0.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param count Number of elements in the array.
- * @param array Array to validate.
- * @param countRequired The 'count' parameter may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T1, typename T2>
-bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                    const ParameterName &arrayName, T1 count, const T2 *array, bool countRequired, bool arrayRequired,
-                    const std::string &count_required_vuid, const std::string &array_required_vuid) {
-    bool skip_call = false;
-
-    // Count parameters not tagged as optional cannot be 0
-    if (countRequired && (count == 0)) {
-        skip_call |=
-            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, count_required_vuid,
-                    "%s: parameter %s must be greater than 0.", apiName, countName.get_name().c_str());
-    }
-
-    // Array parameters not tagged as optional cannot be NULL, unless the count is 0
-    if (arrayRequired && (count != 0) && (*array == NULL)) {
-        skip_call |=
-            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, array_required_vuid,
-                    "%s: required parameter %s specified as NULL.", apiName, arrayName.get_name().c_str());
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate pointer to array count and pointer to array.
- *
- * Verify that required count and array parameters are not NULL.  If count
- * is not NULL and its value is not optional, verify that it is not 0.  If the
- * array parameter is NULL, and it is not optional, verify that count is 0.
- * The array parameter will typically be optional for this case (where count is
- * a pointer), allowing the caller to retrieve the available count.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param count Pointer to the number of elements in the array.
- * @param array Array to validate.
- * @param countPtrRequired The 'count' parameter may not be NULL when true.
- * @param countValueRequired The '*count' value may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T1, typename T2>
-bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                    const ParameterName &arrayName, const T1 *count, const T2 *array, bool countPtrRequired,
-                    bool countValueRequired, bool arrayRequired, const std::string &count_required_vuid,
-                    const std::string &array_required_vuid) {
-    bool skip_call = false;
-
-    if (count == NULL) {
-        if (countPtrRequired) {
-            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
-                                 countName.get_name().c_str());
-        }
-    } else {
-        skip_call |= validate_array(report_data, apiName, countName, arrayName, *array ? (*count) : 0, &array, countValueRequired,
-                                    arrayRequired, count_required_vuid, array_required_vuid);
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate a pointer to a Vulkan structure.
- *
- * Verify that a required pointer to a structure is not NULL.  If the pointer is
- * not NULL, verify that each structure's sType field is set to the correct
- * VkStructureType value.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param parameterName Name of struct parameter being validated.
- * @param sTypeName Name of expected VkStructureType value.
- * @param value Pointer to the struct to validate.
- * @param sType VkStructureType for structure validation.
- * @param required The parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_struct_type(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
-                          const char *sTypeName, const T *value, VkStructureType sType, bool required,
-                          const std::string &struct_vuid, const std::string &stype_vuid) {
-    bool skip_call = false;
-
-    if (value == NULL) {
-        if (required) {
-            skip_call |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, struct_vuid,
-                        "%s: required parameter %s specified as NULL", apiName, parameterName.get_name().c_str());
-        }
-    } else if (value->sType != sType) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
-                             "%s: parameter %s->sType must be %s.", apiName, parameterName.get_name().c_str(), sTypeName);
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate an array of Vulkan structures
- *
- * Verify that required count and array parameters are not 0 or NULL.  If
- * the array contains 1 or more structures, verify that each structure's
- * sType field is set to the correct VkStructureType value.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param sTypeName Name of expected VkStructureType value.
- * @param count Number of elements in the array.
- * @param array Array to validate.
- * @param sType VkStructureType for structure validation.
- * @param countRequired The 'count' parameter may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                                const ParameterName &arrayName, const char *sTypeName, uint32_t count, const T *array,
-                                VkStructureType sType, bool countRequired, bool arrayRequired, const std::string &stype_vuid,
-                                const std::string &param_vuid) {
-    bool skip_call = false;
-
-    if ((count == 0) || (array == NULL)) {
-        skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
-                                    kVUIDUndefined, param_vuid);
-    } else {
-        // Verify that all structs in the array have the correct type
-        for (uint32_t i = 0; i < count; ++i) {
-            if (array[i].sType != sType) {
-                skip_call |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
-                            "%s: parameter %s[%d].sType must be %s", apiName, arrayName.get_name().c_str(), i, sTypeName);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate an array of Vulkan structures.
- *
- * Verify that required count and array parameters are not NULL.  If count
- * is not NULL and its value is not optional, verify that it is not 0.
- * If the array contains 1 or more structures, verify that each structure's
- * sType field is set to the correct VkStructureType value.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param sTypeName Name of expected VkStructureType value.
- * @param count Pointer to the number of elements in the array.
- * @param array Array to validate.
- * @param sType VkStructureType for structure validation.
- * @param countPtrRequired The 'count' parameter may not be NULL when true.
- * @param countValueRequired The '*count' value may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_struct_type_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                                const ParameterName &arrayName, const char *sTypeName, uint32_t *count, const T *array,
-                                VkStructureType sType, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
-                                const std::string &stype_vuid, const std::string &param_vuid) {
-    bool skip_call = false;
-
-    if (count == NULL) {
-        if (countPtrRequired) {
-            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
-                                 countName.get_name().c_str());
-        }
-    } else {
-        skip_call |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
-                                                countValueRequired, arrayRequired, stype_vuid, param_vuid);
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate a Vulkan handle.
- *
- * Verify that the specified handle is not VK_NULL_HANDLE.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param parameter_name Name of struct parameter being validated.
- * @param value Handle to validate.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_required_handle(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, T value) {
-    bool skip_call = false;
-
-    if (value == VK_NULL_HANDLE) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                             kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
-                             parameter_name.get_name().c_str());
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate an array of Vulkan handles.
- *
- * Verify that required count and array parameters are not NULL.  If count
- * is not NULL and its value is not optional, verify that it is not 0.
- * If the array contains 1 or more handles, verify that no handle is set to
- * VK_NULL_HANDLE.
- *
- * @note This function is only intended to validate arrays of handles when none
- *       of the handles are allowed to be VK_NULL_HANDLE.  For arrays of handles
- *       that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param count_name Name of count parameter.
- * @param array_name Name of array parameter.
- * @param count Number of elements in the array.
- * @param array Array to validate.
- * @param count_required The 'count' parameter may not be 0 when true.
- * @param array_required The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_handle_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
-                           const ParameterName &array_name, uint32_t count, const T *array, bool count_required,
-                           bool array_required) {
-    bool skip_call = false;
-
-    if ((count == 0) || (array == NULL)) {
-        skip_call |= validate_array(report_data, api_name, count_name, array_name, count, &array, count_required, array_required,
-                                    kVUIDUndefined, kVUIDUndefined);
-    } else {
-        // Verify that no handles in the array are VK_NULL_HANDLE
-        for (uint32_t i = 0; i < count; ++i) {
-            if (array[i] == VK_NULL_HANDLE) {
-                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                     kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE",
-                                     api_name, array_name.get_name().c_str(), i);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate string array count and content.
- *
- * Verify that required count and array parameters are not 0 or NULL.  If the
- * count parameter is not optional, verify that it is not 0.  If the array
- * parameter is NULL, and it is not optional, verify that count is 0.  If the
- * array parameter is not NULL, verify that none of the strings are NULL.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param count Number of strings in the array.
- * @param array Array of strings to validate.
- * @param countRequired The 'count' parameter may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_string_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                                  const ParameterName &arrayName, uint32_t count, const char *const *array, bool countRequired,
-                                  bool arrayRequired, const std::string &count_required_vuid,
-                                  const std::string &array_required_vuid) {
-    bool skip_call = false;
-
-    if ((count == 0) || (array == NULL)) {
-        skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
-                                    count_required_vuid, array_required_vuid);
-    } else {
-        // Verify that strings in the array are not NULL
-        for (uint32_t i = 0; i < count; ++i) {
-            if (array[i] == NULL) {
-                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                     kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as NULL", apiName,
-                                     arrayName.get_name().c_str(), i);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-// Forward declaration for pNext validation
-bool ValidatePnextStructContents(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
-                                 const GenericHeader *header);
-
-/**
- * Validate a structure's pNext member.
- *
- * Verify that the specified pNext value points to the head of a list of
- * allowed extension structures.  If no extension structures are allowed,
- * verify that pNext is null.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param parameter_name Name of parameter being validated.
- * @param allowed_struct_names Names of allowed structs.
- * @param next Pointer to validate.
- * @param allowed_type_count Total number of allowed structure types.
- * @param allowed_types Array of structure types allowed for pNext.
- * @param header_version Version of header defining the pNext validation rules.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_struct_pnext(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
-                                  const char *allowed_struct_names, const void *next, size_t allowed_type_count,
-                                  const VkStructureType *allowed_types, uint32_t header_version, const std::string &vuid) {
-    bool skip_call = false;
-    std::unordered_set<const void *> cycle_check;
-    std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
-
-    const char disclaimer[] =
-        "This warning is based on the Valid Usage documentation for version %d of the Vulkan header.  It is possible that you are "
-        "using a struct from a private extension or an extension that was added to a later version of the Vulkan header, in which "
-        "case your use of %s is perfectly valid but is not guaranteed to work correctly with validation enabled";
-
-    // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
-    // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms.
-    if (next != NULL) {
-        if (allowed_type_count == 0) {
-            std::string message = "%s: value of %s must be NULL. ";
-            message += disclaimer;
-            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                                 message.c_str(), api_name, parameter_name.get_name().c_str(), header_version,
-                                 parameter_name.get_name().c_str());
-        } else {
-            const VkStructureType *start = allowed_types;
-            const VkStructureType *end = allowed_types + allowed_type_count;
-            const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
-
-            cycle_check.insert(next);
-
-            while (current != NULL) {
-                if (((strncmp(api_name, "vkCreateInstance", strlen(api_name)) != 0) ||
-                     (current->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)) &&
-                    ((strncmp(api_name, "vkCreateDevice", strlen(api_name)) != 0) ||
-                     (current->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO))) {
-                    if (cycle_check.find(current->pNext) != cycle_check.end()) {
-                        std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
-                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                             kVUID_PVError_InvalidStructPNext, message.c_str(), api_name,
-                                             parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
-                        break;
-                    } else {
-                        cycle_check.insert(current->pNext);
-                    }
-
-                    std::string type_name = string_VkStructureType(current->sType);
-                    if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
-                        std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
-                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                             kVUID_PVError_InvalidStructPNext, message.c_str(), api_name,
-                                             parameter_name.get_name().c_str(), type_name.c_str());
-                    } else {
-                        unique_stype_check.insert(current->sType);
-                    }
-
-                    if (std::find(start, end, current->sType) == end) {
-                        if (type_name == UnsupportedStructureTypeString) {
-                            std::string message =
-                                "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are "
-                                "[%s]. ";
-                            message += disclaimer;
-                            skip_call |=
-                                log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                        vuid, message.c_str(), api_name, parameter_name.get_name().c_str(), current->sType,
-                                        allowed_struct_names, header_version, parameter_name.get_name().c_str());
-                        } else {
-                            std::string message =
-                                "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are "
-                                "[%s]. ";
-                            message += disclaimer;
-                            skip_call |=
-                                log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                        vuid, message.c_str(), api_name, parameter_name.get_name().c_str(), type_name.c_str(),
-                                        allowed_struct_names, header_version, parameter_name.get_name().c_str());
-                        }
-                    }
-                    // LUGMAL Insert pNext struct check here:
-                    skip_call |= ValidatePnextStructContents(report_data, api_name, parameter_name, current);
-                }
-                current = reinterpret_cast<const GenericHeader *>(current->pNext);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate a VkBool32 value.
- *
- * Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param parameterName Name of parameter being validated.
- * @param value Boolean value to validate.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_bool32(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
-                            VkBool32 value) {
-    bool skip_call = false;
-
-    if ((value != VK_TRUE) && (value != VK_FALSE)) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                             kVUID_PVError_UnrecognizedValue, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
-                             parameterName.get_name().c_str(), value);
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate a Vulkan enumeration value.
- *
- * Generate a warning if an enumeration token value does not fall within the core enumeration
- * begin and end token values, and was not added to the enumeration by an extension.  Extension
- * provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
- * with 1,000,000,000 as the base token value.
- *
- * @note This function does not expect to process enumerations defining bitmask flag bits.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param parameterName Name of parameter being validated.
- * @param enumName Name of the enumeration being validated.
- * @param valid_values The list of valid values for the enumeration.
- * @param value Enumeration value to validate.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-bool validate_ranged_enum(debug_report_data *report_data, const char *apiName, const ParameterName &parameterName,
-                          const char *enumName, const std::vector<T> &valid_values, T value, const std::string &vuid) {
-    bool skip = false;
-
-    if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                        "%s: value of %s (%d) does not fall within the begin..end range of the core %s enumeration tokens and is "
-                        "not an extension added token.",
-                        apiName, parameterName.get_name().c_str(), value, enumName);
-    }
-
-    return skip;
-}
-
-/**
- * Validate an array of Vulkan enumeration value.
- *
- * Process all enumeration token values in the specified array and generate a warning if a value
- * does not fall within the core enumeration begin and end token values, and was not added to
- * the enumeration by an extension.  Extension provided enumerations use the equation specified
- * in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
- *
- * @note This function does not expect to process enumerations defining bitmask flag bits.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param countName Name of count parameter.
- * @param arrayName Name of array parameter.
- * @param enumName Name of the enumeration being validated.
- * @param valid_values The list of valid values for the enumeration.
- * @param count Number of enumeration values in the array.
- * @param array Array of enumeration values to validate.
- * @param countRequired The 'count' parameter may not be 0 when true.
- * @param arrayRequired The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-template <typename T>
-static bool validate_ranged_enum_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
-                                       const ParameterName &arrayName, const char *enumName, const std::vector<T> &valid_values,
-                                       uint32_t count, const T *array, bool countRequired, bool arrayRequired) {
-    bool skip_call = false;
-
-    if ((count == 0) || (array == NULL)) {
-        skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
-                                    kVUIDUndefined, kVUIDUndefined);
-    } else {
-        for (uint32_t i = 0; i < count; ++i) {
-            if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
-                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                     kVUID_PVError_UnrecognizedValue,
-                                     "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
-                                     "enumeration tokens and is not an extension added token",
-                                     apiName, arrayName.get_name().c_str(), i, array[i], enumName);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-/**
- * Verify that a reserved VkFlags value is zero.
- *
- * Verify that the specified value is zero, to check VkFlags values that are reserved for
- * future use.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param parameter_name Name of parameter being validated.
- * @param value Value to validate.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_reserved_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
-                                    VkFlags value, const std::string &vuid) {
-    bool skip_call = false;
-
-    if (value != 0) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                             "%s: parameter %s must be 0.", api_name, parameter_name.get_name().c_str());
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate a Vulkan bitmask value.
- *
- * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
- * for that type.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param parameter_name Name of parameter being validated.
- * @param flag_bits_name Name of the VkFlags type being validated.
- * @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
- * @param value VkFlags value to validate.
- * @param flags_required The 'value' parameter may not be 0 when true.
- * @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_flags(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name,
-                           const char *flag_bits_name, VkFlags all_flags, VkFlags value, bool flags_required, bool singleFlag,
-                           const std::string &vuid) {
-    bool skip_call = false;
-
-    if (value == 0) {
-        if (flags_required) {
-            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                                 "%s: value of %s must not be 0.", api_name, parameter_name.get_name().c_str());
-        }
-    } else if ((value & (~all_flags)) != 0) {
-        skip_call |=
-            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUID_PVError_UnrecognizedValue, "%s: value of %s contains flag bits that are not recognized members of %s",
-                    api_name, parameter_name.get_name().c_str(), flag_bits_name);
-    } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                             kVUID_PVError_UnrecognizedValue,
-                             "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
-                             parameter_name.get_name().c_str(), flag_bits_name);
-    }
-
-    return skip_call;
-}
-
-/**
- * Validate an array of Vulkan bitmask values.
- *
- * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
- * for that type.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param api_name Name of API call being validated.
- * @param count_name Name of parameter being validated.
- * @param array_name Name of parameter being validated.
- * @param flag_bits_name Name of the VkFlags type being validated.
- * @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
- * @param count Number of VkFlags values in the array.
- * @param array Array of VkFlags value to validate.
- * @param count_required The 'count' parameter may not be 0 when true.
- * @param array_required The 'array' parameter may not be NULL when true.
- * @return Boolean value indicating that the call should be skipped.
- */
-static bool validate_flags_array(debug_report_data *report_data, const char *api_name, const ParameterName &count_name,
-                                 const ParameterName &array_name, const char *flag_bits_name, VkFlags all_flags, uint32_t count,
-                                 const VkFlags *array, bool count_required, bool array_required) {
-    bool skip_call = false;
-
-    if ((count == 0) || (array == NULL)) {
-        skip_call |= validate_array(report_data, api_name, count_name, array_name, count, &array, count_required, array_required,
-                                    kVUIDUndefined, kVUIDUndefined);
-    } else {
-        // Verify that all VkFlags values in the array
-        for (uint32_t i = 0; i < count; ++i) {
-            if (array[i] == 0) {
-                // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
-                // elements in the array are allowed be 0
-                if (array_required) {
-                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                         kVUID_PVError_RequiredParameter, "%s: value of %s[%d] must not be 0", api_name,
-                                         array_name.get_name().c_str(), i);
-                }
-            } else if ((array[i] & (~all_flags)) != 0) {
-                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                                     kVUID_PVError_UnrecognizedValue,
-                                     "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
-                                     array_name.get_name().c_str(), i, flag_bits_name);
-            }
-        }
-    }
-
-    return skip_call;
-}
-
-/**
- * Get VkResult code description.
- *
- * Returns a string describing the specified VkResult code.  The description is based on the language in the Vulkan API
- * specification.
- *
- * @param value VkResult code to process.
- * @return String describing the specified VkResult code.
- */
-static std::string get_result_description(VkResult result) {
-    // clang-format off
-    switch (result) {
-        case VK_SUCCESS:                        return "a command completed successfully";
-        case VK_NOT_READY:                      return "a fence or query has not yet completed";
-        case VK_TIMEOUT:                        return "a wait operation has not completed in the specified time";
-        case VK_EVENT_SET:                      return "an event is signaled";
-        case VK_EVENT_RESET:                    return "an event is unsignalled";
-        case VK_INCOMPLETE:                     return "a return array was too small for the result";
-        case VK_ERROR_OUT_OF_HOST_MEMORY:       return "a host memory allocation has failed";
-        case VK_ERROR_OUT_OF_DEVICE_MEMORY:     return "a device memory allocation has failed";
-        case VK_ERROR_INITIALIZATION_FAILED:    return "initialization of an object has failed";
-        case VK_ERROR_DEVICE_LOST:              return "the logical device has been lost";
-        case VK_ERROR_MEMORY_MAP_FAILED:        return "mapping of a memory object has failed";
-        case VK_ERROR_LAYER_NOT_PRESENT:        return "the specified layer does not exist";
-        case VK_ERROR_EXTENSION_NOT_PRESENT:    return "the specified extension does not exist";
-        case VK_ERROR_FEATURE_NOT_PRESENT:      return "the requested feature is not available on this device";
-        case VK_ERROR_INCOMPATIBLE_DRIVER:      return "a Vulkan driver could not be found";
-        case VK_ERROR_TOO_MANY_OBJECTS:         return "too many objects of the type have already been created";
-        case VK_ERROR_FORMAT_NOT_SUPPORTED:     return "the requested format is not supported on this device";
-        case VK_ERROR_SURFACE_LOST_KHR:         return "a surface is no longer available";
-        case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "the requested window is already connected to another "
-                                                       "VkSurfaceKHR object, or some other non-Vulkan surface object";
-        case VK_SUBOPTIMAL_KHR:                 return "an image became available, and the swapchain no longer "
-                                                       "matches the surface properties exactly, but can still be used to "
-                                                       "present to the surface successfully.";
-        case VK_ERROR_OUT_OF_DATE_KHR:          return "a surface has changed in such a way that it is no "
-                                                       "longer compatible with the swapchain";
-        case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "the display used by a swapchain does not use the same "
-                                                       "presentable image layout, or is incompatible in a way that prevents "
-                                                       "sharing an image";
-        case VK_ERROR_VALIDATION_FAILED_EXT:    return "API validation has detected an invalid use of the API";
-        case VK_ERROR_INVALID_SHADER_NV:        return "one or more shaders failed to compile or link";
-        default:                                return "an error has occurred";
-    };
-    // clang-format on
-}
-
-/**
- * Validate return code.
- *
- * Print a message describing the reason for failure when an error code is returned.
- *
- * @param report_data debug_report_data object for routing validation messages.
- * @param apiName Name of API call being validated.
- * @param ignore vector of VkResult return codes to be ignored
- * @param value VkResult value to validate.
- */
-static void validate_result(debug_report_data *report_data, const char *apiName, std::vector<VkResult> const &ignore,
-                            VkResult result) {
-    if (result < 0 && result != VK_ERROR_VALIDATION_FAILED_EXT) {
-        if (std::find(ignore.begin(), ignore.end(), result) != ignore.end()) {
-            return;
-        }
-        std::string resultName = string_VkResult(result);
-        if (resultName == UnsupportedResultString) {
-            // Unrecognized result code
-            log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUID_PVError_FailureCode, "%s: returned a result code indicating that an error has occurred", apiName);
-        } else {
-            std::string resultDesc = get_result_description(result);
-            log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUID_PVError_FailureCode, "%s: returned %s, indicating that %s", apiName, resultName.c_str(),
-                    resultDesc.c_str());
-        }
-    }
-}
-
-}  // namespace parameter_validation
-
-#endif  // PARAMETER_VALIDATION_UTILS_H
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index 2bb5400..5cc5295 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,121 +16,26 @@
  * limitations under the License.
  *
  * Author: Mark Lobodzinski <mark@LunarG.com>
+ * Author: John Zulauf <jzulauf@lunarg.com>
  */
 
 #define NOMINMAX
 
-#include <limits.h>
 #include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-#include <mutex>
-
-#include "vk_loader_platform.h"
-#include "vulkan/vk_layer.h"
-#include "vk_layer_config.h"
-#include "vk_dispatch_table_helper.h"
-#include "vk_typemap_helper.h"
-
-#include "vk_layer_data.h"
-#include "vk_layer_logging.h"
-#include "vk_layer_extension_utils.h"
-#include "vk_layer_utils.h"
-#include "vk_layer_dispatch_table.h"
-
-#include "parameter_name.h"
-#include "parameter_validation.h"
-
-#if defined __ANDROID__
-#include <android/log.h>
-#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "PARAMETER_VALIDATION", __VA_ARGS__))
-#else
-#define LOGCONSOLE(...)      \
-    {                        \
-        printf(__VA_ARGS__); \
-        printf("\n");        \
-    }
-#endif
-
-namespace parameter_validation {
-
-extern std::unordered_map<std::string, void *> custom_functions;
-
-extern bool parameter_validation_vkCreateInstance(VkInstance instance, const VkInstanceCreateInfo *pCreateInfo,
-                                                  const VkAllocationCallbacks *pAllocator, VkInstance *pInstance);
-extern bool parameter_validation_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator);
-extern bool parameter_validation_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
-                                                const VkAllocationCallbacks *pAllocator, VkDevice *pDevice);
-extern bool parameter_validation_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator);
-extern bool parameter_validation_vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
-                                                   const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool);
-extern bool parameter_validation_vkCreateDebugReportCallbackEXT(VkInstance instance,
-                                                                const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                                const VkAllocationCallbacks *pAllocator,
-                                                                VkDebugReportCallbackEXT *pMsgCallback);
-extern bool parameter_validation_vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                                 const VkAllocationCallbacks *pAllocator);
-extern bool parameter_validation_vkCreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                                const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                                const VkAllocationCallbacks *pAllocator,
-                                                                VkDebugUtilsMessengerEXT *pMessenger);
-extern bool parameter_validation_vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                                 const VkAllocationCallbacks *pAllocator);
-extern bool parameter_validation_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
-                                                     const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool);
-extern bool parameter_validation_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
-extern bool parameter_validation_vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                                                        const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
-extern bool parameter_validation_vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass,
-                                                     const VkAllocationCallbacks *pAllocator);
-
-// TODO : This can be much smarter, using separate locks for separate global data
-std::mutex global_lock;
-
-static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-std::unordered_map<void *, layer_data *> layer_data_map;
-std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;
-
-void InitializeManualParameterValidationFunctionPointers(void);
-
-static void init_parameter_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator,
-                               "lunarg_parameter_validation");
-    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
-                                  "lunarg_parameter_validation");
-}
-
-static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
-                                                            {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
-
-static const VkLayerProperties global_layer = {
-    "VK_LAYER_LUNARG_parameter_validation",
-    VK_LAYER_API_VERSION,
-    1,
-    "LunarG Validation Layer",
-};
-
-enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
+#include "chassis.h"
+#include "stateless_validation.h"
 
 static const int MaxParamCheckerStringLength = 256;
 
 template <typename T>
-static inline bool in_inclusive_range(const T &value, const T &min, const T &max) {
+inline bool in_inclusive_range(const T &value, const T &min, const T &max) {
     // Using only < for generality and || for early abort
     return !((value < min) || (max < value));
 }
 
-static bool validate_string(debug_report_data *report_data, const char *apiName, const ParameterName &stringName,
-                            const std::string &vuid, const char *validateString) {
+bool StatelessValidation::validate_string(const char *apiName, const ParameterName &stringName, const std::string &vuid,
+                                          const char *validateString) {
     bool skip = false;
 
     VkStringErrorFlags result = vk_string_validate(MaxParamCheckerStringLength, validateString);
@@ -147,64 +52,19 @@
     return skip;
 }
 
-static bool ValidateDeviceQueueFamily(layer_data *device_data, uint32_t queue_family, const char *cmd_name,
-                                      const char *parameter_name, const std::string &error_code, bool optional = false) {
-    bool skip = false;
-
-    if (!optional && queue_family == VK_QUEUE_FAMILY_IGNORED) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(device_data->device), error_code,
-                        "%s: %s is VK_QUEUE_FAMILY_IGNORED, but it is required to provide a valid queue family index value.",
-                        cmd_name, parameter_name);
-    } else if (device_data->queueFamilyIndexMap.find(queue_family) == device_data->queueFamilyIndexMap.end()) {
-        skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                    HandleToUint64(device_data->device), error_code,
-                    "%s: %s (= %" PRIu32
-                    ") is not one of the queue families given via VkDeviceQueueCreateInfo structures when the device was created.",
-                    cmd_name, parameter_name, queue_family);
-    }
-
-    return skip;
-}
-
-static bool ValidateQueueFamilies(layer_data *device_data, uint32_t queue_family_count, const uint32_t *queue_families,
-                                  const char *cmd_name, const char *array_parameter_name, const std::string &unique_error_code,
-                                  const std::string &valid_error_code, bool optional = false) {
-    bool skip = false;
-    if (queue_families) {
-        std::unordered_set<uint32_t> set;
-        for (uint32_t i = 0; i < queue_family_count; ++i) {
-            std::string parameter_name = std::string(array_parameter_name) + "[" + std::to_string(i) + "]";
-
-            if (set.count(queue_families[i])) {
-                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                                HandleToUint64(device_data->device), "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372",
-                                "%s: %s (=%" PRIu32 ") is not unique within %s array.", cmd_name, parameter_name.c_str(),
-                                queue_families[i], array_parameter_name);
-            } else {
-                set.insert(queue_families[i]);
-                skip |= ValidateDeviceQueueFamily(device_data, queue_families[i], cmd_name, parameter_name.c_str(),
-                                                  valid_error_code, optional);
-            }
-        }
-    }
-    return skip;
-}
-
-static bool validate_api_version(const instance_layer_data *instance_data, uint32_t api_version, uint32_t effective_api_version) {
+bool StatelessValidation::validate_api_version(uint32_t api_version, uint32_t effective_api_version) {
     bool skip = false;
     uint32_t api_version_nopatch = VK_MAKE_VERSION(VK_VERSION_MAJOR(api_version), VK_VERSION_MINOR(api_version), 0);
     if (api_version_nopatch != effective_api_version) {
         if (api_version_nopatch < VK_API_VERSION_1_0) {
-            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
-                            HandleToUint64(instance_data->instance), kVUIDUndefined,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+                            HandleToUint64(instance), kVUIDUndefined,
                             "Invalid CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). "
                             "Using VK_API_VERSION_%" PRIu32 "_%" PRIu32 ".",
                             api_version, VK_VERSION_MAJOR(effective_api_version), VK_VERSION_MINOR(effective_api_version));
         } else {
-            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
-                            HandleToUint64(instance_data->instance), kVUIDUndefined,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+                            HandleToUint64(instance), kVUIDUndefined,
                             "Unrecognized CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). "
                             "Assuming VK_API_VERSION_%" PRIu32 "_%" PRIu32 ".",
                             api_version, VK_VERSION_MAJOR(effective_api_version), VK_VERSION_MINOR(effective_api_version));
@@ -213,310 +73,125 @@
     return skip;
 }
 
-template <typename ExtensionState>
-static bool validate_extension_reqs(const instance_layer_data *instance_data, const ExtensionState &extensions,
-                                    const std::string &vuid, const char *extension_type, const char *extension_name) {
-    bool skip = false;
-    if (!extension_name) {
-        return skip;  // Robust to invalid char *
-    }
-    auto info = ExtensionState::get_info(extension_name);
-
-    if (!info.state) {
-        return skip;  // Unknown extensions cannot be checked so report OK
-    }
-
-    // Check against the required list in the info
-    std::vector<const char *> missing;
-    for (const auto &req : info.requires) {
-        if (!(extensions.*(req.enabled))) {
-            missing.push_back(req.name);
-        }
-    }
-
-    // Report any missing requirements
-    if (missing.size()) {
-        std::string missing_joined_list = string_join(", ", missing);
-        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
-                        HandleToUint64(instance_data->instance), vuid, "Missing extension%s required by the %s extension %s: %s.",
-                        ((missing.size() > 1) ? "s" : ""), extension_type, extension_name, missing_joined_list.c_str());
-    }
-    return skip;
-}
-
-bool validate_instance_extensions(const instance_layer_data *instance_data, const VkInstanceCreateInfo *pCreateInfo) {
+bool StatelessValidation::validate_instance_extensions(const VkInstanceCreateInfo *pCreateInfo) {
     bool skip = false;
     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        skip |=
-            validate_extension_reqs(instance_data, instance_data->extensions, "VUID-vkCreateInstance-ppEnabledExtensionNames-01388",
-                                    "instance", pCreateInfo->ppEnabledExtensionNames[i]);
+        skip |= validate_extension_reqs(instance_extensions, "VUID-vkCreateInstance-ppEnabledExtensionNames-01388", "instance",
+                                        pCreateInfo->ppEnabledExtensionNames[i]);
     }
 
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                                                VkInstance *pInstance) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-
-    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-    assert(chain_info != nullptr);
-    assert(chain_info->u.pLayerInfo != nullptr);
-
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
-    if (fpCreateInstance == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
-
-    if (result == VK_SUCCESS) {
-        InitializeManualParameterValidationFunctionPointers();
-        auto my_instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
-        assert(my_instance_data != nullptr);
-
-        layer_init_instance_dispatch_table(*pInstance, &my_instance_data->dispatch_table, fpGetInstanceProcAddr);
-        my_instance_data->instance = *pInstance;
-        my_instance_data->report_data =
-            debug_utils_create_instance(&my_instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
-                                        pCreateInfo->ppEnabledExtensionNames);
-
-        // Look for one or more debug report create info structures
-        // and setup a callback(s) for each one found.
-        if (!layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &my_instance_data->num_tmp_debug_messengers,
-                                             &my_instance_data->tmp_messenger_create_infos,
-                                             &my_instance_data->tmp_debug_messengers)) {
-            if (my_instance_data->num_tmp_debug_messengers > 0) {
-                // Setup the temporary callback(s) here to catch early issues:
-                if (layer_enable_tmp_debug_messengers(my_instance_data->report_data, my_instance_data->num_tmp_debug_messengers,
-                                                      my_instance_data->tmp_messenger_create_infos,
-                                                      my_instance_data->tmp_debug_messengers)) {
-                    // Failure of setting up one or more of the callback.
-                    // Therefore, clean up and don't use those callbacks:
-                    layer_free_tmp_debug_messengers(my_instance_data->tmp_messenger_create_infos,
-                                                    my_instance_data->tmp_debug_messengers);
-                    my_instance_data->num_tmp_debug_messengers = 0;
-                }
-            }
-        }
-        if (!layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &my_instance_data->num_tmp_report_callbacks,
-                                             &my_instance_data->tmp_report_create_infos, &my_instance_data->tmp_report_callbacks)) {
-            if (my_instance_data->num_tmp_report_callbacks > 0) {
-                // Setup the temporary callback(s) here to catch early issues:
-                if (layer_enable_tmp_report_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_report_callbacks,
-                                                      my_instance_data->tmp_report_create_infos,
-                                                      my_instance_data->tmp_report_callbacks)) {
-                    // Failure of setting up one or more of the callback.
-                    // Therefore, clean up and don't use those callbacks:
-                    layer_free_tmp_report_callbacks(my_instance_data->tmp_report_create_infos,
-                                                    my_instance_data->tmp_report_callbacks);
-                    my_instance_data->num_tmp_report_callbacks = 0;
-                }
-            }
-        }
-
-        init_parameter_validation(my_instance_data, pAllocator);
-        // Note: From the spec--
-        //  Providing a NULL VkInstanceCreateInfo::pApplicationInfo or providing an apiVersion of 0 is equivalent to providing
-        //  an apiVersion of VK_MAKE_VERSION(1, 0, 0).  (a.k.a. VK_API_VERSION_1_0)
-        uint32_t api_version = (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion)
-                                   ? pCreateInfo->pApplicationInfo->apiVersion
-                                   : VK_API_VERSION_1_0;
-
-        my_instance_data->api_version = my_instance_data->extensions.InitFromInstanceCreateInfo(api_version, pCreateInfo);
-
-        // Ordinarily we'd check these before calling down the chain, but none of the layer support is in place until now, if we
-        // survive we can report the issue now.
-        validate_api_version(my_instance_data, api_version, my_instance_data->api_version);
-        validate_instance_extensions(my_instance_data, pCreateInfo);
-
-        parameter_validation_vkCreateInstance(*pInstance, pCreateInfo, pAllocator, pInstance);
-
-        if (pCreateInfo->pApplicationInfo) {
-            if (pCreateInfo->pApplicationInfo->pApplicationName) {
-                validate_string(
-                    my_instance_data->report_data, "vkCreateInstance", "pCreateInfo->VkApplicationInfo->pApplicationName",
-                    "VUID-VkApplicationInfo-pApplicationName-parameter", pCreateInfo->pApplicationInfo->pApplicationName);
-            }
-
-            if (pCreateInfo->pApplicationInfo->pEngineName) {
-                validate_string(my_instance_data->report_data, "vkCreateInstance", "pCreateInfo->VkApplicationInfo->pEngineName",
-                                "VUID-VkApplicationInfo-pEngineName-parameter", pCreateInfo->pApplicationInfo->pEngineName);
-            }
-        }
-
-        // Disable the tmp callbacks:
-        if (my_instance_data->num_tmp_debug_messengers > 0) {
-            layer_disable_tmp_debug_messengers(my_instance_data->report_data, my_instance_data->num_tmp_debug_messengers,
-                                               my_instance_data->tmp_debug_messengers);
-        }
-        if (my_instance_data->num_tmp_report_callbacks > 0) {
-            layer_disable_tmp_report_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_report_callbacks,
-                                               my_instance_data->tmp_report_callbacks);
-        }
-    }
-
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    // Grab the key before the instance is destroyed.
-    dispatch_key key = get_dispatch_key(instance);
-    bool skip = false;
-    auto instance_data = GetLayerDataPtr(key, instance_layer_data_map);
-
-    // Enable the temporary callback(s) here to catch vkDestroyInstance issues:
-    bool callback_setup = false;
-    if (instance_data->num_tmp_debug_messengers > 0) {
-        if (!layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                               instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers)) {
-            callback_setup = true;
-        }
-    }
-    if (instance_data->num_tmp_report_callbacks > 0) {
-        if (!layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                               instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks)) {
-            callback_setup = true;
-        }
-    }
-
-    skip |= parameter_validation_vkDestroyInstance(instance, pAllocator);
-
-    // Disable and cleanup the temporary callback(s):
-    if (callback_setup) {
-        layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                           instance_data->tmp_debug_messengers);
-        layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                           instance_data->tmp_report_callbacks);
-    }
-    if (instance_data->num_tmp_debug_messengers > 0) {
-        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
-        instance_data->num_tmp_debug_messengers = 0;
-    }
-    if (instance_data->num_tmp_report_callbacks > 0) {
-        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
-        instance_data->num_tmp_report_callbacks = 0;
-    }
-
-    if (!skip) {
-        instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
-
-        // Clean up logging callback, if any
-        while (instance_data->logging_messenger.size() > 0) {
-            VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
-            layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-            instance_data->logging_messenger.pop_back();
-        }
-        while (instance_data->logging_callback.size() > 0) {
-            VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-            layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
-            instance_data->logging_callback.pop_back();
-        }
-
-        layer_debug_utils_destroy_instance(instance_data->report_data);
-    }
-
-    FreeLayerDataPtr(key, instance_layer_data_map);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
-                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugReportCallbackEXT *pMsgCallback) {
-    bool skip = parameter_validation_vkCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult result = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-    if (result == VK_SUCCESS) {
-        result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
-        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
-        if (VK_SUCCESS != result) {
-            instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, *pMsgCallback, pAllocator);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    bool skip = parameter_validation_vkDestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-    if (!skip) {
-        auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-        instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-        layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                              const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugUtilsMessengerEXT *pMessenger) {
-    bool skip = parameter_validation_vkCreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult result = instance_data->dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-    if (VK_SUCCESS == result) {
-        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
-        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
-        if (VK_SUCCESS != result) {
-            instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, *pMessenger, pAllocator);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    bool skip = parameter_validation_vkDestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-    if (!skip) {
-        auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-        instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-    }
-}
-
 template <typename ExtensionState>
-static bool extension_state_by_name(const ExtensionState &extensions, const char *extension_name) {
+bool extension_state_by_name(const ExtensionState &extensions, const char *extension_name) {
     if (!extension_name) return false;  // null strings specify nothing
     auto info = ExtensionState::get_info(extension_name);
     bool state = info.state ? extensions.*(info.state) : false;  // unknown extensions can't be enabled in extension struct
     return state;
 }
 
-static bool ValidateDeviceCreateInfo(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
-                                     const VkDeviceCreateInfo *pCreateInfo, const DeviceExtensions &extensions) {
+bool StatelessValidation::manual_PreCallValidateCreateInstance(const VkInstanceCreateInfo *pCreateInfo,
+                                                               const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
+    bool skip = false;
+    // Note: From the spec--
+    //  Providing a NULL VkInstanceCreateInfo::pApplicationInfo or providing an apiVersion of 0 is equivalent to providing
+    //  an apiVersion of VK_MAKE_VERSION(1, 0, 0).  (a.k.a. VK_API_VERSION_1_0)
+    uint32_t local_api_version = (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion)
+                                     ? pCreateInfo->pApplicationInfo->apiVersion
+                                     : VK_API_VERSION_1_0;
+    skip |= validate_api_version(local_api_version, api_version);
+    skip |= validate_instance_extensions(pCreateInfo);
+    return skip;
+}
+
+void StatelessValidation::PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo,
+                                                       const VkAllocationCallbacks *pAllocator, VkInstance *pInstance,
+                                                       VkResult result) {
+    auto instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
+    // Copy extension data into local object
+    if (result != VK_SUCCESS) return;
+    this->instance_extensions = instance_data->instance_extensions;
+}
+
+void StatelessValidation::PostCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
+    auto device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
+    if (result != VK_SUCCESS) return;
+    ValidationObject *validation_data = GetValidationObject(device_data->object_dispatch, LayerObjectTypeParameterValidation);
+    StatelessValidation *stateless_validation = static_cast<StatelessValidation *>(validation_data);
+
+    // Parmeter validation also uses extension data
+    stateless_validation->device_extensions = this->device_extensions;
+
+    VkPhysicalDeviceProperties device_properties = {};
+    // Need to get instance and do a getlayerdata call...
+    ValidationObject *instance_object = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
+    instance_object->instance_dispatch_table.GetPhysicalDeviceProperties(physicalDevice, &device_properties);
+    memcpy(&stateless_validation->device_limits, &device_properties.limits, sizeof(VkPhysicalDeviceLimits));
+
+    if (device_extensions.vk_nv_shading_rate_image) {
+        // Get the needed shading rate image limits
+        auto shading_rate_image_props = lvl_init_struct<VkPhysicalDeviceShadingRateImagePropertiesNV>();
+        auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&shading_rate_image_props);
+        instance_object->instance_dispatch_table.GetPhysicalDeviceProperties2KHR(physicalDevice, &prop2);
+        phys_dev_ext_props.shading_rate_image_props = shading_rate_image_props;
+    }
+
+    if (device_extensions.vk_nv_mesh_shader) {
+        // Get the needed mesh shader limits
+        auto mesh_shader_props = lvl_init_struct<VkPhysicalDeviceMeshShaderPropertiesNV>();
+        auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&mesh_shader_props);
+        instance_object->instance_dispatch_table.GetPhysicalDeviceProperties2KHR(physicalDevice, &prop2);
+        phys_dev_ext_props.mesh_shader_props = mesh_shader_props;
+    }
+
+    stateless_validation->phys_dev_ext_props = this->phys_dev_ext_props;
+
+    // Save app-enabled features in this device's validation object
+    // The enabled features can come from either pEnabledFeatures, or from the pNext chain
+    const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
+    if ((nullptr == enabled_features_found) && device_extensions.vk_khr_get_physical_device_properties_2) {
+        const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
+        if (features2) {
+            enabled_features_found = &(features2->features);
+        }
+    }
+    if (enabled_features_found) {
+        stateless_validation->physical_device_features = *enabled_features_found;
+    } else {
+        memset(&stateless_validation->physical_device_features, 0, sizeof(VkPhysicalDeviceFeatures));
+    }
+}
+
+bool StatelessValidation::manual_PreCallValidateCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
+                                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
     bool skip = false;
     bool maint1 = false;
     bool negative_viewport = false;
 
     if ((pCreateInfo->enabledLayerCount > 0) && (pCreateInfo->ppEnabledLayerNames != NULL)) {
         for (size_t i = 0; i < pCreateInfo->enabledLayerCount; i++) {
-            skip |= validate_string(instance_data->report_data, "vkCreateDevice", "pCreateInfo->ppEnabledLayerNames",
+            skip |= validate_string("vkCreateDevice", "pCreateInfo->ppEnabledLayerNames",
                                     "VUID-VkDeviceCreateInfo-ppEnabledLayerNames-parameter", pCreateInfo->ppEnabledLayerNames[i]);
         }
     }
 
     if ((pCreateInfo->enabledExtensionCount > 0) && (pCreateInfo->ppEnabledExtensionNames != NULL)) {
-        maint1 = extension_state_by_name(extensions, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
-        negative_viewport = extension_state_by_name(extensions, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME);
+        maint1 = extension_state_by_name(device_extensions, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        negative_viewport = extension_state_by_name(device_extensions, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME);
 
         for (size_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-            skip |= validate_string(instance_data->report_data, "vkCreateDevice", "pCreateInfo->ppEnabledExtensionNames",
+            skip |= validate_string("vkCreateDevice", "pCreateInfo->ppEnabledExtensionNames",
                                     "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-parameter",
                                     pCreateInfo->ppEnabledExtensionNames[i]);
-            skip |= validate_extension_reqs(instance_data, extensions, "VUID-vkCreateDevice-ppEnabledExtensionNames-01387",
-                                            "device", pCreateInfo->ppEnabledExtensionNames[i]);
+            skip |= validate_extension_reqs(device_extensions, "VUID-vkCreateDevice-ppEnabledExtensionNames-01387", "device",
+                                            pCreateInfo->ppEnabledExtensionNames[i]);
         }
     }
 
     if (maint1 && negative_viewport) {
-        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374",
                         "VkDeviceCreateInfo->ppEnabledExtensionNames must not simultaneously include VK_KHR_maintenance1 and "
                         "VK_AMD_negative_viewport_height.");
@@ -527,7 +202,7 @@
         const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
         if (features2) {
             // Cannot include VkPhysicalDeviceFeatures2KHR and have non-null pEnabledFeatures
-            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             kVUID_PVError_InvalidUsage,
                             "VkDeviceCreateInfo->pNext includes a VkPhysicalDeviceFeatures2KHR struct when "
                             "pCreateInfo->pEnabledFeatures is non-NULL.");
@@ -541,17 +216,15 @@
         for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) {
             const uint32_t requested_queue_family = pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex;
             if (requested_queue_family == VK_QUEUE_FAMILY_IGNORED) {
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
-                                "VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381",
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                                HandleToUint64(physicalDevice), "VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381",
                                 "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32
                                 "].queueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, but it is required to provide a valid queue family "
                                 "index value.",
                                 i);
             } else if (set.count(requested_queue_family)) {
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
-                                "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372",
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                                HandleToUint64(physicalDevice), "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372",
                                 "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueFamilyIndex (=%" PRIu32
                                 ") is not unique within pCreateInfo->pQueueCreateInfos array.",
                                 i, requested_queue_family);
@@ -563,9 +236,8 @@
                 for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; ++j) {
                     const float queue_priority = pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[j];
                     if (!(queue_priority >= 0.f) || !(queue_priority <= 1.f)) {
-                        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice),
-                                        "VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383",
+                        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                                        HandleToUint64(physicalDevice), "VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383",
                                         "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].pQueuePriorities[%" PRIu32
                                         "] (=%f) is not between 0 and 1 (inclusive).",
                                         i, j, queue_priority);
@@ -578,303 +250,22 @@
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
-                                              const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
-    // NOTE: Don't validate physicalDevice or any dispatchable object as the first parameter. We couldn't get here if it was wrong!
-
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    bool skip = false;
-    auto my_instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    assert(my_instance_data != nullptr);
-
-    // Query and save physical device limits for this device, needed for validation
-    VkPhysicalDeviceProperties device_properties = {};
-    my_instance_data->dispatch_table.GetPhysicalDeviceProperties(physicalDevice, &device_properties);
-
-    // Setup the validation tables based on the application API version from the instance and the capabilities of the device driver.
-    uint32_t effective_api_version = std::min(device_properties.apiVersion, my_instance_data->api_version);
-    DeviceExtensions extensions;
-    uint32_t api_version = extensions.InitFromDeviceCreateInfo(&my_instance_data->extensions, effective_api_version, pCreateInfo);
-
-    std::unique_lock<std::mutex> lock(global_lock);
-
-    skip |= parameter_validation_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
-
-    if (pCreateInfo != NULL) skip |= ValidateDeviceCreateInfo(my_instance_data, physicalDevice, pCreateInfo, extensions);
-
-    if (!skip) {
-        VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-        assert(chain_info != nullptr);
-        assert(chain_info->u.pLayerInfo != nullptr);
-
-        PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-        PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
-        PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
-        if (fpCreateDevice == NULL) {
-            return VK_ERROR_INITIALIZATION_FAILED;
-        }
-
-        // Advance the link info for the next element on the chain
-        chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-        lock.unlock();
-
-        result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
-
-        lock.lock();
-
-        if (result == VK_SUCCESS) {
-            layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-            assert(my_device_data != nullptr);
-
-            my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
-            layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
-
-            my_device_data->api_version = api_version;
-            my_device_data->extensions = extensions;
-
-            // Store createdevice data
-            if ((pCreateInfo != nullptr) && (pCreateInfo->pQueueCreateInfos != nullptr)) {
-                for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) {
-                    my_device_data->queueFamilyIndexMap.insert(std::make_pair(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,
-                                                                              pCreateInfo->pQueueCreateInfos[i].queueCount));
-                }
-            }
-
-            memcpy(&my_device_data->device_limits, &device_properties.limits, sizeof(VkPhysicalDeviceLimits));
-            my_device_data->physical_device = physicalDevice;
-            my_device_data->device = *pDevice;
-
-            if (my_device_data->extensions.vk_nv_shading_rate_image) {
-                // Get the needed shading rate image limits
-                auto shading_rate_image_props = lvl_init_struct<VkPhysicalDeviceShadingRateImagePropertiesNV>();
-                auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&shading_rate_image_props);
-                my_instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(physicalDevice, &prop2);
-                my_device_data->phys_dev_ext_props.shading_rate_image_props = shading_rate_image_props;
-            }
-
-            if (my_device_data->extensions.vk_nv_mesh_shader) {
-                // Get the needed mesh shader limits
-                auto mesh_shader_props = lvl_init_struct<VkPhysicalDeviceMeshShaderPropertiesNV>();
-                auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&mesh_shader_props);
-                my_instance_data->dispatch_table.GetPhysicalDeviceProperties2KHR(physicalDevice, &prop2);
-                my_device_data->phys_dev_ext_props.mesh_shader_props = mesh_shader_props;
-            }
-
-            // Save app-enabled features in this device's layer_data structure
-            // The enabled features can come from either pEnabledFeatures, or from the pNext chain
-            const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
-            if ((nullptr == enabled_features_found) && my_device_data->extensions.vk_khr_get_physical_device_properties_2) {
-                const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
-                if (features2) {
-                    enabled_features_found = &(features2->features);
-                }
-            }
-            if (enabled_features_found) {
-                my_device_data->physical_device_features = *enabled_features_found;
-            } else {
-                memset(&my_device_data->physical_device_features, 0, sizeof(VkPhysicalDeviceFeatures));
-            }
-        }
+bool StatelessValidation::require_device_extension(bool flag, char const *function_name, char const *extension_name) {
+    if (!flag) {
+        return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                       kVUID_PVError_ExtensionNotEnabled,
+                       "%s() called even though the %s extension was not enabled for this VkDevice.", function_name,
+                       extension_name);
     }
 
-    return result;
+    return false;
 }
 
-VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(device);
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(key, layer_data_map);
-    {
-        std::unique_lock<std::mutex> lock(global_lock);
-        skip |= parameter_validation_vkDestroyDevice(device, pAllocator);
-    }
-
-    if (!skip) {
-        layer_debug_utils_destroy_device(device);
-        device_data->dispatch_table.DestroyDevice(device, pAllocator);
-    }
-    FreeLayerDataPtr(key, layer_data_map);
-}
-
-bool pv_vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    skip |= ValidateDeviceQueueFamily(device_data, queueFamilyIndex, "vkGetDeviceQueue", "queueFamilyIndex",
-                                      "VUID-vkGetDeviceQueue-queueFamilyIndex-00384");
-    const auto &queue_data = device_data->queueFamilyIndexMap.find(queueFamilyIndex);
-    if (queue_data != device_data->queueFamilyIndexMap.end() && queue_data->second <= queueIndex) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
-                        HandleToUint64(device), "VUID-vkGetDeviceQueue-queueIndex-00385",
-                        "vkGetDeviceQueue: queueIndex (=%" PRIu32
-                        ") is not less than the number of queues requested from queueFamilyIndex (=%" PRIu32
-                        ") when the device was created (i.e. is not less than %" PRIu32 ").",
-                        queueIndex, queueFamilyIndex, queue_data->second);
-    }
-    return skip;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
-                                                   const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
-    layer_data *local_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = false;
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    std::unique_lock<std::mutex> lock(global_lock);
-
-    skip |= ValidateDeviceQueueFamily(local_data, pCreateInfo->queueFamilyIndex, "vkCreateCommandPool",
-                                      "pCreateInfo->queueFamilyIndex", "VUID-vkCreateCommandPool-queueFamilyIndex-01937");
-
-    skip |= parameter_validation_vkCreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
-
-    lock.unlock();
-    if (!skip) {
-        result = local_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
-                                                 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    skip |= parameter_validation_vkCreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
-
-    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
-    if (pCreateInfo != nullptr) {
-        // If queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, pipelineStatistics must be a valid combination of
-        // VkQueryPipelineStatisticFlagBits values
-        if ((pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) && (pCreateInfo->pipelineStatistics != 0) &&
-            ((pCreateInfo->pipelineStatistics & (~AllVkQueryPipelineStatisticFlagBits)) != 0)) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            "VUID-VkQueryPoolCreateInfo-queryType-00792",
-                            "vkCreateQueryPool(): if pCreateInfo->queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, "
-                            "pCreateInfo->pipelineStatistics must be a valid combination of VkQueryPipelineStatisticFlagBits "
-                            "values.");
-        }
-    }
-    if (!skip) {
-        result = device_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
-    }
-    return result;
-}
-
-template <typename T>
-static void RecordRenderPass(layer_data *device_data, VkRenderPass renderPass, const T *pCreateInfo) {
-    auto &renderpass_state = device_data->renderpasses_states[renderPass];
-
-    for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
-        bool uses_color = false;
-        for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
-            if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
-
-        bool uses_depthstencil = false;
-        if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
-            if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
-                uses_depthstencil = true;
-
-        if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
-        if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                                  const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = false;
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-
-    {
-        std::unique_lock<std::mutex> lock(global_lock);
-        skip |= parameter_validation_vkCreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
-
-        typedef bool (*PFN_manual_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                                      const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
-        PFN_manual_vkCreateRenderPass custom_func = (PFN_manual_vkCreateRenderPass)custom_functions["vkCreateRenderPass"];
-        if (custom_func != nullptr) {
-            skip |= custom_func(device, pCreateInfo, pAllocator, pRenderPass);
-        }
-    }
-
-    if (!skip) {
-        result = device_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
-
-        // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
-        if (result == VK_SUCCESS) {
-            std::unique_lock<std::mutex> lock(global_lock);
-            RecordRenderPass(device_data, *pRenderPass, pCreateInfo);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                                                      const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    bool skip = false;
-    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
-
-    {
-        std::unique_lock<std::mutex> lock(global_lock);
-        skip |= parameter_validation_vkCreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
-
-        typedef bool (*PFN_manual_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                                                          const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
-        PFN_manual_vkCreateRenderPass2KHR custom_func =
-            (PFN_manual_vkCreateRenderPass2KHR)custom_functions["vkCreateRenderPass2KHR"];
-        if (custom_func != nullptr) {
-            skip |= custom_func(device, pCreateInfo, pAllocator, pRenderPass);
-        }
-    }
-
-    if (!skip) {
-        result = device_data->dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
-
-        // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
-        if (result == VK_SUCCESS) {
-            std::unique_lock<std::mutex> lock(global_lock);
-            RecordRenderPass(device_data, *pRenderPass, pCreateInfo);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool StatelessValidation::manual_PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
+                                                             const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
     bool skip = false;
 
-    {
-        std::unique_lock<std::mutex> lock(global_lock);
-        skip |= parameter_validation_vkDestroyRenderPass(device, renderPass, pAllocator);
-
-        typedef bool (*PFN_manual_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass,
-                                                       const VkAllocationCallbacks *pAllocator);
-        PFN_manual_vkDestroyRenderPass custom_func = (PFN_manual_vkDestroyRenderPass)custom_functions["vkDestroyRenderPass"];
-        if (custom_func != nullptr) {
-            skip |= custom_func(device, renderPass, pAllocator);
-        }
-    }
-
-    if (!skip) {
-        device_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
-
-        // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
-        {
-            std::unique_lock<std::mutex> lock(global_lock);
-            device_data->renderpasses_states.erase(renderPass);
-        }
-    }
-}
-
-bool pv_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                       VkBuffer *pBuffer) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
-    const LogMiscParams log_misc{report_data, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, VK_NULL_HANDLE, "vkCreateBuffer"};
+    const LogMiscParams log_misc{VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, VK_NULL_HANDLE, "vkCreateBuffer"};
 
     if (pCreateInfo != nullptr) {
         skip |= ValidateGreaterThanZero(pCreateInfo->size, "pCreateInfo->size", "VUID-VkBufferCreateInfo-size-00912", log_misc);
@@ -897,10 +288,6 @@
                                 "vkCreateBuffer: if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
                                 "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of "
                                 "pCreateInfo->queueFamilyIndexCount uint32_t values.");
-            } else {
-                skip |= ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
-                                              "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", kVUID_PVError_InvalidUsage,
-                                              kVUID_PVError_InvalidUsage, false);
             }
         }
 
@@ -918,13 +305,11 @@
     return skip;
 }
 
-bool pv_vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                      VkImage *pImage) {
+bool StatelessValidation::manual_PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
-    const LogMiscParams log_misc{report_data, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, VK_NULL_HANDLE, "vkCreateImage"};
+    const LogMiscParams log_misc{VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, VK_NULL_HANDLE, "vkCreateImage"};
 
     if (pCreateInfo != nullptr) {
         // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
@@ -945,10 +330,6 @@
                                 "vkCreateImage(): if pCreateInfo->sharingMode is VK_SHARING_MODE_CONCURRENT, "
                                 "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of "
                                 "pCreateInfo->queueFamilyIndexCount uint32_t values.");
-            } else {
-                skip |= ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
-                                              "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", kVUID_PVError_InvalidUsage,
-                                              kVUID_PVError_InvalidUsage, false);
             }
         }
 
@@ -1065,7 +446,7 @@
                             "pCreateInfo->imageType is not VK_IMAGE_TYPE_3D.");
         }
 
-        if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) && (!device_data->physical_device_features.sparseBinding)) {
+        if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) && (!physical_device_features.sparseBinding)) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, VK_NULL_HANDLE,
                             "VUID-VkImageCreateInfo-flags-00969",
                             "vkCreateImage(): pCreateInfo->flags contains VK_IMAGE_CREATE_SPARSE_BINDING_BIT, but the "
@@ -1100,8 +481,7 @@
             }
 
             // Sparse 2D image when device doesn't support it
-            if ((VK_FALSE == device_data->physical_device_features.sparseResidencyImage2D) &&
-                (VK_IMAGE_TYPE_2D == pCreateInfo->imageType)) {
+            if ((VK_FALSE == physical_device_features.sparseResidencyImage2D) && (VK_IMAGE_TYPE_2D == pCreateInfo->imageType)) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 "VUID-VkImageCreateInfo-imageType-00971",
                                 "vkCreateImage: cannot specify VK_IMAGE_CREATE_SPARSE_BINDING_BIT for 2D image if corresponding "
@@ -1109,8 +489,7 @@
             }
 
             // Sparse 3D image when device doesn't support it
-            if ((VK_FALSE == device_data->physical_device_features.sparseResidencyImage3D) &&
-                (VK_IMAGE_TYPE_3D == pCreateInfo->imageType)) {
+            if ((VK_FALSE == physical_device_features.sparseResidencyImage3D) && (VK_IMAGE_TYPE_3D == pCreateInfo->imageType)) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 "VUID-VkImageCreateInfo-imageType-00972",
                                 "vkCreateImage: cannot specify VK_IMAGE_CREATE_SPARSE_BINDING_BIT for 3D image if corresponding "
@@ -1119,25 +498,25 @@
 
             // Multi-sample 2D image when device doesn't support it
             if (VK_IMAGE_TYPE_2D == pCreateInfo->imageType) {
-                if ((VK_FALSE == device_data->physical_device_features.sparseResidency2Samples) &&
+                if ((VK_FALSE == physical_device_features.sparseResidency2Samples) &&
                     (VK_SAMPLE_COUNT_2_BIT == pCreateInfo->samples)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkImageCreateInfo-imageType-00973",
                                     "vkCreateImage: cannot specify VK_IMAGE_CREATE_SPARSE_BINDING_BIT for 2-sample image if "
                                     "corresponding feature is not enabled on the device.");
-                } else if ((VK_FALSE == device_data->physical_device_features.sparseResidency4Samples) &&
+                } else if ((VK_FALSE == physical_device_features.sparseResidency4Samples) &&
                            (VK_SAMPLE_COUNT_4_BIT == pCreateInfo->samples)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkImageCreateInfo-imageType-00974",
                                     "vkCreateImage: cannot specify VK_IMAGE_CREATE_SPARSE_BINDING_BIT for 4-sample image if "
                                     "corresponding feature is not enabled on the device.");
-                } else if ((VK_FALSE == device_data->physical_device_features.sparseResidency8Samples) &&
+                } else if ((VK_FALSE == physical_device_features.sparseResidency8Samples) &&
                            (VK_SAMPLE_COUNT_8_BIT == pCreateInfo->samples)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkImageCreateInfo-imageType-00975",
                                     "vkCreateImage: cannot specify VK_IMAGE_CREATE_SPARSE_BINDING_BIT for 8-sample image if "
                                     "corresponding feature is not enabled on the device.");
-                } else if ((VK_FALSE == device_data->physical_device_features.sparseResidency16Samples) &&
+                } else if ((VK_FALSE == physical_device_features.sparseResidency16Samples) &&
                            (VK_SAMPLE_COUNT_16_BIT == pCreateInfo->samples)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkImageCreateInfo-imageType-00976",
@@ -1204,11 +583,9 @@
     return skip;
 }
 
-bool pv_vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                          VkImageView *pView) {
+bool StatelessValidation::manual_PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
+                                                                const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
     if (pCreateInfo != nullptr) {
         // Validate chained VkImageViewUsageCreateInfo struct, if present
@@ -1232,10 +609,10 @@
     return skip;
 }
 
-bool pv_VkViewport(const layer_data *device_data, const VkViewport &viewport, const char *fn_name, const char *param_name,
-                   VkDebugReportObjectTypeEXT object_type, uint64_t object = 0) {
+bool StatelessValidation::manual_PreCallValidateViewport(const VkViewport &viewport, const char *fn_name,
+                                                         const ParameterName &parameter_name,
+                                                         VkDebugReportObjectTypeEXT object_type, uint64_t object = 0) {
     bool skip = false;
-    debug_report_data *report_data = device_data->report_data;
 
     // Note: for numerical correctness
     //       - float comparisons should expect NaN (comparison always false).
@@ -1268,42 +645,41 @@
 
     // width
     bool width_healthy = true;
-    const auto max_w = device_data->device_limits.maxViewportDimensions[0];
+    const auto max_w = device_limits.maxViewportDimensions[0];
 
     if (!(viewport.width > 0.0f)) {
         width_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-width-01770",
-                        "%s: %s.width (=%f) is not greater than 0.0.", fn_name, param_name, viewport.width);
+                        "%s: %s.width (=%f) is not greater than 0.0.", fn_name, parameter_name.get_name().c_str(), viewport.width);
     } else if (!(f_lte_u32_exact(viewport.width, max_w) || f_lte_u32_direct(viewport.width, max_w))) {
         width_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-width-01771",
                         "%s: %s.width (=%f) exceeds VkPhysicalDeviceLimits::maxViewportDimensions[0] (=%" PRIu32 ").", fn_name,
-                        param_name, viewport.width, max_w);
+                        parameter_name.get_name().c_str(), viewport.width, max_w);
     } else if (!f_lte_u32_exact(viewport.width, max_w) && f_lte_u32_direct(viewport.width, max_w)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, object_type, object, kVUID_PVError_NONE,
                         "%s: %s.width (=%f) technically exceeds VkPhysicalDeviceLimits::maxViewportDimensions[0] (=%" PRIu32
                         "), but it is within the static_cast<float>(maxViewportDimensions[0]) limit.",
-                        fn_name, param_name, viewport.width, max_w);
+                        fn_name, parameter_name.get_name().c_str(), viewport.width, max_w);
     }
 
     // height
     bool height_healthy = true;
-    const bool negative_height_enabled = device_data->api_version >= VK_API_VERSION_1_1 ||
-                                         device_data->extensions.vk_khr_maintenance1 ||
-                                         device_data->extensions.vk_amd_negative_viewport_height;
-    const auto max_h = device_data->device_limits.maxViewportDimensions[1];
+    const bool negative_height_enabled = api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1 ||
+                                         device_extensions.vk_amd_negative_viewport_height;
+    const auto max_h = device_limits.maxViewportDimensions[1];
 
     if (!negative_height_enabled && !(viewport.height > 0.0f)) {
         height_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-height-01772",
-                        "%s: %s.height (=%f) is not greater 0.0.", fn_name, param_name, viewport.height);
+                        "%s: %s.height (=%f) is not greater 0.0.", fn_name, parameter_name.get_name().c_str(), viewport.height);
     } else if (!(f_lte_u32_exact(fabsf(viewport.height), max_h) || f_lte_u32_direct(fabsf(viewport.height), max_h))) {
         height_healthy = false;
 
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-height-01773",
                         "%s: Absolute value of %s.height (=%f) exceeds VkPhysicalDeviceLimits::maxViewportDimensions[1] (=%" PRIu32
                         ").",
-                        fn_name, param_name, viewport.height, max_h);
+                        fn_name, parameter_name.get_name().c_str(), viewport.height, max_h);
     } else if (!f_lte_u32_exact(fabsf(viewport.height), max_h) && f_lte_u32_direct(fabsf(viewport.height), max_h)) {
         height_healthy = false;
 
@@ -1311,69 +687,70 @@
             report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, object_type, object, kVUID_PVError_NONE,
             "%s: Absolute value of %s.height (=%f) technically exceeds VkPhysicalDeviceLimits::maxViewportDimensions[1] (=%" PRIu32
             "), but it is within the static_cast<float>(maxViewportDimensions[1]) limit.",
-            fn_name, param_name, viewport.height, max_h);
+            fn_name, parameter_name.get_name().c_str(), viewport.height, max_h);
     }
 
     // x
     bool x_healthy = true;
-    if (!(viewport.x >= device_data->device_limits.viewportBoundsRange[0])) {
+    if (!(viewport.x >= device_limits.viewportBoundsRange[0])) {
         x_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-x-01774",
-                        "%s: %s.x (=%f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).", fn_name, param_name,
-                        viewport.x, device_data->device_limits.viewportBoundsRange[0]);
+                        "%s: %s.x (=%f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).", fn_name,
+                        parameter_name.get_name().c_str(), viewport.x, device_limits.viewportBoundsRange[0]);
     }
 
     // x + width
     if (x_healthy && width_healthy) {
         const float right_bound = viewport.x + viewport.width;
-        if (!(right_bound <= device_data->device_limits.viewportBoundsRange[1])) {
+        if (!(right_bound <= device_limits.viewportBoundsRange[1])) {
             skip |=
                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-x-01232",
                         "%s: %s.x + %s.width (=%f + %f = %f) is greater than VkPhysicalDeviceLimits::viewportBoundsRange[1] (=%f).",
-                        fn_name, param_name, param_name, viewport.x, viewport.width, right_bound,
-                        device_data->device_limits.viewportBoundsRange[1]);
+                        fn_name, parameter_name.get_name().c_str(), parameter_name.get_name().c_str(), viewport.x, viewport.width,
+                        right_bound, device_limits.viewportBoundsRange[1]);
         }
     }
 
     // y
     bool y_healthy = true;
-    if (!(viewport.y >= device_data->device_limits.viewportBoundsRange[0])) {
+    if (!(viewport.y >= device_limits.viewportBoundsRange[0])) {
         y_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-y-01775",
-                        "%s: %s.y (=%f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).", fn_name, param_name,
-                        viewport.y, device_data->device_limits.viewportBoundsRange[0]);
-    } else if (negative_height_enabled && !(viewport.y <= device_data->device_limits.viewportBoundsRange[1])) {
+                        "%s: %s.y (=%f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).", fn_name,
+                        parameter_name.get_name().c_str(), viewport.y, device_limits.viewportBoundsRange[0]);
+    } else if (negative_height_enabled && !(viewport.y <= device_limits.viewportBoundsRange[1])) {
         y_healthy = false;
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-y-01776",
-                        "%s: %s.y (=%f) exceeds VkPhysicalDeviceLimits::viewportBoundsRange[1] (=%f).", fn_name, param_name,
-                        viewport.y, device_data->device_limits.viewportBoundsRange[1]);
+                        "%s: %s.y (=%f) exceeds VkPhysicalDeviceLimits::viewportBoundsRange[1] (=%f).", fn_name,
+                        parameter_name.get_name().c_str(), viewport.y, device_limits.viewportBoundsRange[1]);
     }
 
     // y + height
     if (y_healthy && height_healthy) {
         const float boundary = viewport.y + viewport.height;
 
-        if (!(boundary <= device_data->device_limits.viewportBoundsRange[1])) {
+        if (!(boundary <= device_limits.viewportBoundsRange[1])) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-y-01233",
                             "%s: %s.y + %s.height (=%f + %f = %f) exceeds VkPhysicalDeviceLimits::viewportBoundsRange[1] (=%f).",
-                            fn_name, param_name, param_name, viewport.y, viewport.height, boundary,
-                            device_data->device_limits.viewportBoundsRange[1]);
-        } else if (negative_height_enabled && !(boundary >= device_data->device_limits.viewportBoundsRange[0])) {
-            skip |= log_msg(
-                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-y-01777",
-                "%s: %s.y + %s.height (=%f + %f = %f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).", fn_name,
-                param_name, param_name, viewport.y, viewport.height, boundary, device_data->device_limits.viewportBoundsRange[0]);
+                            fn_name, parameter_name.get_name().c_str(), parameter_name.get_name().c_str(), viewport.y,
+                            viewport.height, boundary, device_limits.viewportBoundsRange[1]);
+        } else if (negative_height_enabled && !(boundary >= device_limits.viewportBoundsRange[0])) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-y-01777",
+                        "%s: %s.y + %s.height (=%f + %f = %f) is less than VkPhysicalDeviceLimits::viewportBoundsRange[0] (=%f).",
+                        fn_name, parameter_name.get_name().c_str(), parameter_name.get_name().c_str(), viewport.y, viewport.height,
+                        boundary, device_limits.viewportBoundsRange[0]);
         }
     }
 
-    if (!device_data->extensions.vk_ext_depth_range_unrestricted) {
+    if (!device_extensions.vk_ext_depth_range_unrestricted) {
         // minDepth
         if (!(viewport.minDepth >= 0.0) || !(viewport.minDepth <= 1.0)) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object, "VUID-VkViewport-minDepth-01234",
 
                             "%s: VK_EXT_depth_range_unrestricted extension is not enabled and %s.minDepth (=%f) is not within the "
                             "[0.0, 1.0] range.",
-                            fn_name, param_name, viewport.minDepth);
+                            fn_name, parameter_name.get_name().c_str(), viewport.minDepth);
         }
 
         // maxDepth
@@ -1382,7 +759,7 @@
 
                             "%s: VK_EXT_depth_range_unrestricted extension is not enabled and %s.maxDepth (=%f) is not within the "
                             "[0.0, 1.0] range.",
-                            fn_name, param_name, viewport.maxDepth);
+                            fn_name, parameter_name.get_name().c_str(), viewport.maxDepth);
         }
     }
 
@@ -1405,9 +782,8 @@
     {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, 4, 4},
 };
 
-bool ValidateCoarseSampleOrderCustomNV(layer_data *device_data, const VkCoarseSampleOrderCustomNV *order) {
+bool StatelessValidation::ValidateCoarseSampleOrderCustomNV(const VkCoarseSampleOrderCustomNV *order) {
     bool skip = false;
-    debug_report_data *report_data = device_data->report_data;
 
     SampleOrderInfo *sampleOrderInfo;
     uint32_t infoIdx = 0;
@@ -1427,7 +803,7 @@
     }
 
     if (order->sampleCount == 0 || (order->sampleCount & (order->sampleCount - 1)) ||
-        !(order->sampleCount & device_data->device_limits.framebufferNoAttachmentsSampleCounts)) {
+        !(order->sampleCount & device_limits.framebufferNoAttachmentsSampleCounts)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkCoarseSampleOrderCustomNV-sampleCount-02074",
                         "VkCoarseSampleOrderCustomNV sampleCount (=%" PRIu32
@@ -1448,21 +824,21 @@
                         order->sampleLocationCount, order->sampleCount, sampleOrderInfo->width, sampleOrderInfo->height);
     }
 
-    if (order->sampleLocationCount > device_data->phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples) {
+    if (order->sampleLocationCount > phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples) {
         skip |= log_msg(
             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
             "VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02076",
             "VkCoarseSampleOrderCustomNV sampleLocationCount (=%" PRIu32
             ") must "
             "be less than or equal to VkPhysicalDeviceShadingRateImagePropertiesNV shadingRateMaxCoarseSamples (=%" PRIu32 ").",
-            order->sampleLocationCount, device_data->phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples);
+            order->sampleLocationCount, phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples);
     }
 
     // Accumulate a bitmask tracking which (x,y,sample) tuples are seen. Expect
     // the first width*height*sampleCount bits to all be set. Note: There is no
     // guarantee that 64 bits is enough, but practically it's unlikely for an
     // implementation to support more than 32 bits for samplemask.
-    assert(device_data->phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples <= 64);
+    assert(phys_dev_ext_props.shading_rate_image_props.shadingRateMaxCoarseSamples <= 64);
     uint64_t sampleLocationsMask = 0;
     for (uint32_t i = 0; i < order->sampleLocationCount; ++i) {
         const VkCoarseSampleLocationNV *sampleLoc = &order->pSampleLocations[i];
@@ -1497,12 +873,12 @@
     return skip;
 }
 
-bool pv_vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                  const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
-                                  VkPipeline *pPipelines) {
+bool StatelessValidation::manual_PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache,
+                                                                        uint32_t createInfoCount,
+                                                                        const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                                        const VkAllocationCallbacks *pAllocator,
+                                                                        VkPipeline *pPipelines) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
     if (pCreateInfos != nullptr) {
         for (uint32_t i = 0; i < createInfoCount; ++i) {
@@ -1534,24 +910,22 @@
             if (pCreateInfos[i].pVertexInputState != nullptr) {
                 auto const &vertex_input_state = pCreateInfos[i].pVertexInputState;
 
-                if (vertex_input_state->vertexBindingDescriptionCount > device_data->device_limits.maxVertexInputBindings) {
+                if (vertex_input_state->vertexBindingDescriptionCount > device_limits.maxVertexInputBindings) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkPipelineVertexInputStateCreateInfo-vertexBindingDescriptionCount-00613",
                                     "vkCreateGraphicsPipelines: pararameter "
                                     "pCreateInfo[%d].pVertexInputState->vertexBindingDescriptionCount (%u) is "
                                     "greater than VkPhysicalDeviceLimits::maxVertexInputBindings (%u).",
-                                    i, vertex_input_state->vertexBindingDescriptionCount,
-                                    device_data->device_limits.maxVertexInputBindings);
+                                    i, vertex_input_state->vertexBindingDescriptionCount, device_limits.maxVertexInputBindings);
                 }
 
-                if (vertex_input_state->vertexAttributeDescriptionCount > device_data->device_limits.maxVertexInputAttributes) {
+                if (vertex_input_state->vertexAttributeDescriptionCount > device_limits.maxVertexInputAttributes) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     "VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614",
                                     "vkCreateGraphicsPipelines: pararameter "
                                     "pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptionCount (%u) is "
                                     "greater than VkPhysicalDeviceLimits::maxVertexInputAttributes (%u).",
-                                    i, vertex_input_state->vertexBindingDescriptionCount,
-                                    device_data->device_limits.maxVertexInputAttributes);
+                                    i, vertex_input_state->vertexBindingDescriptionCount, device_limits.maxVertexInputAttributes);
                 }
 
                 std::unordered_set<uint32_t> vertex_bindings(vertex_input_state->vertexBindingDescriptionCount);
@@ -1568,22 +942,22 @@
                     }
                     vertex_bindings.insert(vertex_bind_desc.binding);
 
-                    if (vertex_bind_desc.binding >= device_data->device_limits.maxVertexInputBindings) {
+                    if (vertex_bind_desc.binding >= device_limits.maxVertexInputBindings) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                         "VUID-VkVertexInputBindingDescription-binding-00618",
                                         "vkCreateGraphicsPipelines: parameter "
                                         "pCreateInfos[%u].pVertexInputState->pVertexBindingDescriptions[%u].binding (%u) is "
                                         "greater than or equal to VkPhysicalDeviceLimits::maxVertexInputBindings (%u).",
-                                        i, d, vertex_bind_desc.binding, device_data->device_limits.maxVertexInputBindings);
+                                        i, d, vertex_bind_desc.binding, device_limits.maxVertexInputBindings);
                     }
 
-                    if (vertex_bind_desc.stride > device_data->device_limits.maxVertexInputBindingStride) {
+                    if (vertex_bind_desc.stride > device_limits.maxVertexInputBindingStride) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                         "VUID-VkVertexInputBindingDescription-stride-00619",
                                         "vkCreateGraphicsPipelines: parameter "
                                         "pCreateInfos[%u].pVertexInputState->pVertexBindingDescriptions[%u].stride (%u) is greater "
                                         "than VkPhysicalDeviceLimits::maxVertexInputBindingStride (%u).",
-                                        i, d, vertex_bind_desc.stride, device_data->device_limits.maxVertexInputBindingStride);
+                                        i, d, vertex_bind_desc.stride, device_limits.maxVertexInputBindingStride);
                     }
                 }
 
@@ -1612,31 +986,31 @@
                             i, d, vertex_attrib_desc.binding, i);
                     }
 
-                    if (vertex_attrib_desc.location >= device_data->device_limits.maxVertexInputAttributes) {
+                    if (vertex_attrib_desc.location >= device_limits.maxVertexInputAttributes) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                         "VUID-VkVertexInputAttributeDescription-location-00620",
                                         "vkCreateGraphicsPipelines: parameter "
                                         "pCreateInfos[%u].pVertexInputState->pVertexAttributeDescriptions[%u].location (%u) is "
                                         "greater than or equal to VkPhysicalDeviceLimits::maxVertexInputAttributes (%u).",
-                                        i, d, vertex_attrib_desc.location, device_data->device_limits.maxVertexInputAttributes);
+                                        i, d, vertex_attrib_desc.location, device_limits.maxVertexInputAttributes);
                     }
 
-                    if (vertex_attrib_desc.binding >= device_data->device_limits.maxVertexInputBindings) {
+                    if (vertex_attrib_desc.binding >= device_limits.maxVertexInputBindings) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                         "VUID-VkVertexInputAttributeDescription-binding-00621",
                                         "vkCreateGraphicsPipelines: parameter "
                                         "pCreateInfos[%u].pVertexInputState->pVertexAttributeDescriptions[%u].binding (%u) is "
                                         "greater than or equal to VkPhysicalDeviceLimits::maxVertexInputBindings (%u).",
-                                        i, d, vertex_attrib_desc.binding, device_data->device_limits.maxVertexInputBindings);
+                                        i, d, vertex_attrib_desc.binding, device_limits.maxVertexInputBindings);
                     }
 
-                    if (vertex_attrib_desc.offset > device_data->device_limits.maxVertexInputAttributeOffset) {
+                    if (vertex_attrib_desc.offset > device_limits.maxVertexInputAttributeOffset) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                         "VUID-VkVertexInputAttributeDescription-offset-00622",
                                         "vkCreateGraphicsPipelines: parameter "
                                         "pCreateInfos[%u].pVertexInputState->pVertexAttributeDescriptions[%u].offset (%u) is "
                                         "greater than VkPhysicalDeviceLimits::maxVertexInputAttributeOffset (%u).",
-                                        i, d, vertex_attrib_desc.offset, device_data->device_limits.maxVertexInputAttributeOffset);
+                                        i, d, vertex_attrib_desc.offset, device_limits.maxVertexInputAttributeOffset);
                     }
                 }
             }
@@ -1664,13 +1038,13 @@
                                         i, i);
                     } else {
                         skip |= validate_struct_pnext(
-                            report_data, "vkCreateGraphicsPipelines",
+                            "vkCreateGraphicsPipelines",
                             ParameterName("pCreateInfos[%i].pTessellationState->pNext", ParameterName::IndexVector{i}), NULL,
-                            pCreateInfos[i].pTessellationState->pNext, 0, NULL, GeneratedHeaderVersion,
+                            pCreateInfos[i].pTessellationState->pNext, 0, NULL, GeneratedVulkanHeaderVersion,
                             "VUID-VkGraphicsPipelineCreateInfo-pNext-pNext");
 
                         skip |= validate_reserved_flags(
-                            report_data, "vkCreateGraphicsPipelines",
+                            "vkCreateGraphicsPipelines",
                             ParameterName("pCreateInfos[%i].pTessellationState->flags", ParameterName::IndexVector{i}),
                             pCreateInfos[i].pTessellationState->flags,
                             "VUID-VkPipelineTessellationStateCreateInfo-flags-zerobitmask");
@@ -1685,15 +1059,14 @@
                         }
 
                         if (pCreateInfos[i].pTessellationState->patchControlPoints == 0 ||
-                            pCreateInfos[i].pTessellationState->patchControlPoints >
-                                device_data->device_limits.maxTessellationPatchSize) {
+                            pCreateInfos[i].pTessellationState->patchControlPoints > device_limits.maxTessellationPatchSize) {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                             "VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214",
                                             "vkCreateGraphicsPipelines: invalid parameter "
                                             "pCreateInfos[%d].pTessellationState->patchControlPoints value %u. patchControlPoints "
                                             "should be >0 and <=%u.",
                                             i, pCreateInfos[i].pTessellationState->patchControlPoints,
-                                            device_data->device_limits.maxTessellationPatchSize);
+                                            device_limits.maxTessellationPatchSize);
                         }
                     }
                 }
@@ -1728,7 +1101,7 @@
                         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV,
                     };
                     skip |= validate_struct_pnext(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pViewportState->pNext", ParameterName::IndexVector{i}),
                         "VkPipelineViewportSwizzleStateCreateInfoNV, VkPipelineViewportWScalingStateCreateInfoNV, "
                         "VkPipelineViewportExclusiveScissorStateCreateInfoNV, VkPipelineViewportShadingRateImageStateCreateInfoNV, "
@@ -1738,7 +1111,7 @@
                         "VUID-VkPipelineViewportStateCreateInfo-pNext-pNext");
 
                     skip |= validate_reserved_flags(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pViewportState->flags", ParameterName::IndexVector{i}),
                         viewport_state.flags, "VUID-VkPipelineViewportStateCreateInfo-flags-zerobitmask");
 
@@ -1748,8 +1121,10 @@
                         pCreateInfos[i].pViewportState->pNext);
                     auto coarse_sample_order_struct = lvl_find_in_chain<VkPipelineViewportCoarseSampleOrderStateCreateInfoNV>(
                         pCreateInfos[i].pViewportState->pNext);
+                    const auto vp_swizzle_struct =
+                        lvl_find_in_chain<VkPipelineViewportSwizzleStateCreateInfoNV>(pCreateInfos[i].pViewportState->pNext);
 
-                    if (!device_data->physical_device_features.multiViewport) {
+                    if (!physical_device_features.multiViewport) {
                         if (viewport_state.viewportCount != 1) {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                             VK_NULL_HANDLE, "VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216",
@@ -1799,13 +1174,13 @@
                                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                 VK_NULL_HANDLE, "VUID-VkPipelineViewportStateCreateInfo-viewportCount-arraylength",
                                 "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32 "].pViewportState->viewportCount is 0.", i);
-                        } else if (viewport_state.viewportCount > device_data->device_limits.maxViewports) {
+                        } else if (viewport_state.viewportCount > device_limits.maxViewports) {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                             VK_NULL_HANDLE, "VUID-VkPipelineViewportStateCreateInfo-viewportCount-01218",
                                             "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
                                             "].pViewportState->viewportCount (=%" PRIu32
                                             ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                                            i, viewport_state.viewportCount, device_data->device_limits.maxViewports);
+                                            i, viewport_state.viewportCount, device_limits.maxViewports);
                         }
 
                         if (viewport_state.scissorCount == 0) {
@@ -1813,35 +1188,33 @@
                                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                 VK_NULL_HANDLE, "VUID-VkPipelineViewportStateCreateInfo-scissorCount-arraylength",
                                 "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32 "].pViewportState->scissorCount is 0.", i);
-                        } else if (viewport_state.scissorCount > device_data->device_limits.maxViewports) {
+                        } else if (viewport_state.scissorCount > device_limits.maxViewports) {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                             VK_NULL_HANDLE, "VUID-VkPipelineViewportStateCreateInfo-scissorCount-01219",
                                             "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
                                             "].pViewportState->scissorCount (=%" PRIu32
                                             ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                                            i, viewport_state.scissorCount, device_data->device_limits.maxViewports);
+                                            i, viewport_state.scissorCount, device_limits.maxViewports);
                         }
                     }
 
-                    if (exclusive_scissor_struct &&
-                        exclusive_scissor_struct->exclusiveScissorCount > device_data->device_limits.maxViewports) {
-                        skip |= log_msg(
-                            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, VK_NULL_HANDLE,
-                            "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02028",
-                            "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32 "] exclusiveScissorCount (=%" PRIu32
-                            ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                            i, exclusive_scissor_struct->exclusiveScissorCount, device_data->device_limits.maxViewports);
+                    if (exclusive_scissor_struct && exclusive_scissor_struct->exclusiveScissorCount > device_limits.maxViewports) {
+                        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                        VK_NULL_HANDLE,
+                                        "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02028",
+                                        "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32 "] exclusiveScissorCount (=%" PRIu32
+                                        ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
+                                        i, exclusive_scissor_struct->exclusiveScissorCount, device_limits.maxViewports);
                     }
 
-                    if (shading_rate_image_struct &&
-                        shading_rate_image_struct->viewportCount > device_data->device_limits.maxViewports) {
+                    if (shading_rate_image_struct && shading_rate_image_struct->viewportCount > device_limits.maxViewports) {
                         skip |=
                             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                     VK_NULL_HANDLE, "VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-viewportCount-02055",
                                     "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
                                     "] VkPipelineViewportShadingRateImageStateCreateInfoNV viewportCount (=%" PRIu32
                                     ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                                    i, shading_rate_image_struct->viewportCount, device_data->device_limits.maxViewports);
+                                    i, shading_rate_image_struct->viewportCount, device_limits.maxViewports);
                     }
 
                     if (viewport_state.scissorCount != viewport_state.viewportCount) {
@@ -1920,19 +1293,30 @@
                             i, i);
                     }
 
+                    if (vp_swizzle_struct) {
+                        if (vp_swizzle_struct->viewportCount != viewport_state.viewportCount) {
+                            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                            VK_NULL_HANDLE, "VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-01215",
+                                            "vkCreateGraphicsPipelines: The viewport swizzle state vieport count of %" PRIu32
+                                            " does "
+                                            "not match the viewport count of %" PRIu32 " in VkPipelineViewportStateCreateInfo.",
+                                            vp_swizzle_struct->viewportCount, viewport_state.viewportCount);
+                        }
+                    }
+
                     // validate the VkViewports
                     if (!has_dynamic_viewport && viewport_state.pViewports) {
                         for (uint32_t viewport_i = 0; viewport_i < viewport_state.viewportCount; ++viewport_i) {
                             const auto &viewport = viewport_state.pViewports[viewport_i];  // will crash on invalid ptr
-                            const char fn_name[] = "vkCreateGraphicsPipelines";
-                            const std::string param_name = "pCreateInfos[" + std::to_string(i) + "].pViewportState->pViewports[" +
-                                                           std::to_string(viewport_i) + "]";
-                            skip |= pv_VkViewport(device_data, viewport, fn_name, param_name.c_str(),
-                                                  VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT);
+                            const char *fn_name = "vkCreateGraphicsPipelines";
+                            skip |= manual_PreCallValidateViewport(viewport, fn_name,
+                                                                   ParameterName("pCreateInfos[%i].pViewportState->pViewports[%i]",
+                                                                                 ParameterName::IndexVector{i, viewport_i}),
+                                                                   VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT);
                         }
                     }
 
-                    if (has_dynamic_viewport_w_scaling_nv && !device_data->extensions.vk_nv_clip_space_w_scaling) {
+                    if (has_dynamic_viewport_w_scaling_nv && !device_extensions.vk_nv_clip_space_w_scaling) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                         VK_NULL_HANDLE, kVUID_PVError_ExtensionNotEnabled,
                                         "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
@@ -1941,7 +1325,7 @@
                                         i);
                     }
 
-                    if (has_dynamic_discard_rectangle_ext && !device_data->extensions.vk_ext_discard_rectangles) {
+                    if (has_dynamic_discard_rectangle_ext && !device_extensions.vk_ext_discard_rectangles) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                         VK_NULL_HANDLE, kVUID_PVError_ExtensionNotEnabled,
                                         "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
@@ -1950,7 +1334,7 @@
                                         i);
                     }
 
-                    if (has_dynamic_sample_locations_ext && !device_data->extensions.vk_ext_sample_locations) {
+                    if (has_dynamic_sample_locations_ext && !device_extensions.vk_ext_sample_locations) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                         VK_NULL_HANDLE, kVUID_PVError_ExtensionNotEnabled,
                                         "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
@@ -1959,7 +1343,7 @@
                                         i);
                     }
 
-                    if (has_dynamic_exclusive_scissor_nv && !device_data->extensions.vk_nv_scissor_exclusive) {
+                    if (has_dynamic_exclusive_scissor_nv && !device_extensions.vk_nv_scissor_exclusive) {
                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                                         VK_NULL_HANDLE, kVUID_PVError_ExtensionNotEnabled,
                                         "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
@@ -1983,8 +1367,7 @@
 
                     if (coarse_sample_order_struct) {
                         for (uint32_t order_i = 0; order_i < coarse_sample_order_struct->customSampleOrderCount; ++order_i) {
-                            skip |= ValidateCoarseSampleOrderCustomNV(device_data,
-                                                                      &coarse_sample_order_struct->pCustomSampleOrders[order_i]);
+                            skip |= ValidateCoarseSampleOrderCustomNV(&coarse_sample_order_struct->pCustomSampleOrders[order_i]);
                         }
                     }
                 }
@@ -2003,35 +1386,35 @@
                         "VkPipelineCoverageModulationStateCreateInfoNV, VkPipelineCoverageToColorStateCreateInfoNV, "
                         "VkPipelineSampleLocationsStateCreateInfoEXT";
                     skip |= validate_struct_pnext(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->pNext", ParameterName::IndexVector{i}),
-                        valid_struct_names, pCreateInfos[i].pMultisampleState->pNext, 3, valid_next_stypes, GeneratedHeaderVersion,
-                        "VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext");
+                        valid_struct_names, pCreateInfos[i].pMultisampleState->pNext, 3, valid_next_stypes,
+                        GeneratedVulkanHeaderVersion, "VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext");
 
                     skip |= validate_reserved_flags(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->flags", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pMultisampleState->flags, "VUID-VkPipelineMultisampleStateCreateInfo-flags-zerobitmask");
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->sampleShadingEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pMultisampleState->sampleShadingEnable);
 
                     skip |= validate_array(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->rasterizationSamples", ParameterName::IndexVector{i}),
                         ParameterName("pCreateInfos[%i].pMultisampleState->pSampleMask", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pMultisampleState->rasterizationSamples, &pCreateInfos[i].pMultisampleState->pSampleMask,
                         true, false, kVUIDUndefined, kVUIDUndefined);
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->alphaToCoverageEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pMultisampleState->alphaToCoverageEnable);
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pMultisampleState->alphaToOneEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pMultisampleState->alphaToOneEnable);
 
@@ -2043,7 +1426,7 @@
                                         i);
                     }
                     if (pCreateInfos[i].pMultisampleState->sampleShadingEnable == VK_TRUE) {
-                        if (!device_data->physical_device_features.sampleRateShading) {
+                        if (!physical_device_features.sampleRateShading) {
                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                             "VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784",
                                             "vkCreateGraphicsPipelines(): parameter "
@@ -2064,98 +1447,100 @@
                 bool uses_color_attachment = false;
                 bool uses_depthstencil_attachment = false;
                 {
-                    const auto subpasses_uses_it = device_data->renderpasses_states.find(pCreateInfos[i].renderPass);
-                    if (subpasses_uses_it != device_data->renderpasses_states.end()) {
+                    std::unique_lock<std::mutex> lock(renderpass_map_mutex);
+                    const auto subpasses_uses_it = renderpasses_states.find(pCreateInfos[i].renderPass);
+                    if (subpasses_uses_it != renderpasses_states.end()) {
                         const auto &subpasses_uses = subpasses_uses_it->second;
                         if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[i].subpass))
                             uses_color_attachment = true;
                         if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[i].subpass))
                             uses_depthstencil_attachment = true;
                     }
+                    lock.unlock();
                 }
 
                 if (pCreateInfos[i].pDepthStencilState != nullptr && uses_depthstencil_attachment) {
                     skip |= validate_struct_pnext(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->pNext", ParameterName::IndexVector{i}), NULL,
-                        pCreateInfos[i].pDepthStencilState->pNext, 0, NULL, GeneratedHeaderVersion,
+                        pCreateInfos[i].pDepthStencilState->pNext, 0, NULL, GeneratedVulkanHeaderVersion,
                         "VUID-VkPipelineDepthStencilStateCreateInfo-pNext-pNext");
 
                     skip |= validate_reserved_flags(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->flags", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pDepthStencilState->flags, "VUID-VkPipelineDepthStencilStateCreateInfo-flags-zerobitmask");
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->depthTestEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pDepthStencilState->depthTestEnable);
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->depthWriteEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pDepthStencilState->depthWriteEnable);
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->depthCompareOp", ParameterName::IndexVector{i}),
                         "VkCompareOp", AllVkCompareOpEnums, pCreateInfos[i].pDepthStencilState->depthCompareOp,
                         "VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter");
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->depthBoundsTestEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pDepthStencilState->depthBoundsTestEnable);
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->stencilTestEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pDepthStencilState->stencilTestEnable);
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->front.failOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->front.failOp,
                         "VUID-VkStencilOpState-failOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->front.passOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->front.passOp,
                         "VUID-VkStencilOpState-passOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->front.depthFailOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->front.depthFailOp,
                         "VUID-VkStencilOpState-depthFailOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->front.compareOp", ParameterName::IndexVector{i}),
                         "VkCompareOp", AllVkCompareOpEnums, pCreateInfos[i].pDepthStencilState->front.compareOp,
                         "VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->back.failOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->back.failOp,
                         "VUID-VkStencilOpState-failOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->back.passOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->back.passOp,
                         "VUID-VkStencilOpState-passOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->back.depthFailOp", ParameterName::IndexVector{i}),
                         "VkStencilOp", AllVkStencilOpEnums, pCreateInfos[i].pDepthStencilState->back.depthFailOp,
                         "VUID-VkStencilOpState-depthFailOp-parameter");
 
                     skip |= validate_ranged_enum(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->back.compareOp", ParameterName::IndexVector{i}),
                         "VkCompareOp", AllVkCompareOpEnums, pCreateInfos[i].pDepthStencilState->back.compareOp,
                         "VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter");
@@ -2174,25 +1559,25 @@
 
                 if (pCreateInfos[i].pColorBlendState != nullptr && uses_color_attachment) {
                     skip |= validate_struct_pnext(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pColorBlendState->pNext", ParameterName::IndexVector{i}),
                         "VkPipelineColorBlendAdvancedStateCreateInfoEXT", pCreateInfos[i].pColorBlendState->pNext,
                         ARRAY_SIZE(allowed_structs_VkPipelineColorBlendStateCreateInfo),
-                        allowed_structs_VkPipelineColorBlendStateCreateInfo, GeneratedHeaderVersion,
+                        allowed_structs_VkPipelineColorBlendStateCreateInfo, GeneratedVulkanHeaderVersion,
                         "VUID-VkPipelineColorBlendStateCreateInfo-pNext-pNext");
 
                     skip |= validate_reserved_flags(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pColorBlendState->flags", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pColorBlendState->flags, "VUID-VkPipelineColorBlendStateCreateInfo-flags-zerobitmask");
 
                     skip |= validate_bool32(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pColorBlendState->logicOpEnable", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pColorBlendState->logicOpEnable);
 
                     skip |= validate_array(
-                        report_data, "vkCreateGraphicsPipelines",
+                        "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pColorBlendState->attachmentCount", ParameterName::IndexVector{i}),
                         ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments", ParameterName::IndexVector{i}),
                         pCreateInfos[i].pColorBlendState->attachmentCount, &pCreateInfos[i].pColorBlendState->pAttachments, false,
@@ -2201,13 +1586,13 @@
                     if (pCreateInfos[i].pColorBlendState->pAttachments != NULL) {
                         for (uint32_t attachmentIndex = 0; attachmentIndex < pCreateInfos[i].pColorBlendState->attachmentCount;
                              ++attachmentIndex) {
-                            skip |= validate_bool32(report_data, "vkCreateGraphicsPipelines",
+                            skip |= validate_bool32("vkCreateGraphicsPipelines",
                                                     ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].blendEnable",
                                                                   ParameterName::IndexVector{i, attachmentIndex}),
                                                     pCreateInfos[i].pColorBlendState->pAttachments[attachmentIndex].blendEnable);
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].srcColorBlendFactor",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendFactor", AllVkBlendFactorEnums,
@@ -2215,7 +1600,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter");
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].dstColorBlendFactor",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendFactor", AllVkBlendFactorEnums,
@@ -2223,7 +1608,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter");
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].colorBlendOp",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendOp", AllVkBlendOpEnums,
@@ -2231,7 +1616,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter");
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].srcAlphaBlendFactor",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendFactor", AllVkBlendFactorEnums,
@@ -2239,7 +1624,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter");
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].dstAlphaBlendFactor",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendFactor", AllVkBlendFactorEnums,
@@ -2247,7 +1632,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter");
 
                             skip |= validate_ranged_enum(
-                                report_data, "vkCreateGraphicsPipelines",
+                                "vkCreateGraphicsPipelines",
                                 ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].alphaBlendOp",
                                               ParameterName::IndexVector{i, attachmentIndex}),
                                 "VkBlendOp", AllVkBlendOpEnums,
@@ -2255,7 +1640,7 @@
                                 "VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter");
 
                             skip |=
-                                validate_flags(report_data, "vkCreateGraphicsPipelines",
+                                validate_flags("vkCreateGraphicsPipelines",
                                                ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments[%i].colorWriteMask",
                                                              ParameterName::IndexVector{i, attachmentIndex}),
                                                "VkColorComponentFlagBits", AllVkColorComponentFlagBits,
@@ -2275,7 +1660,7 @@
                     // If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value
                     if (pCreateInfos[i].pColorBlendState->logicOpEnable == VK_TRUE) {
                         skip |= validate_ranged_enum(
-                            report_data, "vkCreateGraphicsPipelines",
+                            "vkCreateGraphicsPipelines",
                             ParameterName("pCreateInfos[%i].pColorBlendState->logicOp", ParameterName::IndexVector{i}), "VkLogicOp",
                             AllVkLogicOpEnums, pCreateInfos[i].pColorBlendState->logicOp,
                             "VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607");
@@ -2307,7 +1692,7 @@
 
             if (pCreateInfos[i].pRasterizationState) {
                 if ((pCreateInfos[i].pRasterizationState->polygonMode != VK_POLYGON_MODE_FILL) &&
-                    (device_data->physical_device_features.fillModeNonSolid == false)) {
+                    (physical_device_features.fillModeNonSolid == false)) {
                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                     kVUID_PVError_DeviceFeature,
                                     "vkCreateGraphicsPipelines parameter, VkPolygonMode "
@@ -2315,21 +1700,20 @@
                                     "VK_POLYGON_MODE_LINE if VkPhysicalDeviceFeatures->fillModeNonSolid is false.");
                 }
 
-                if (!has_dynamic_line_width && !device_data->physical_device_features.wideLines &&
+                if (!has_dynamic_line_width && !physical_device_features.wideLines &&
                     (pCreateInfos[i].pRasterizationState->lineWidth != 1.0f)) {
-                    skip |=
-                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
-                                0, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749",
-                                "The line width state is static (pCreateInfos[%" PRIu32
-                                "].pDynamicState->pDynamicStates does not contain VK_DYNAMIC_STATE_LINE_WIDTH) and "
-                                "VkPhysicalDeviceFeatures::wideLines is disabled, but pCreateInfos[%" PRIu32
-                                "].pRasterizationState->lineWidth (=%f) is not 1.0.",
-                                i, i, pCreateInfos[i].pRasterizationState->lineWidth);
+                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, 0,
+                                    "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749",
+                                    "The line width state is static (pCreateInfos[%" PRIu32
+                                    "].pDynamicState->pDynamicStates does not contain VK_DYNAMIC_STATE_LINE_WIDTH) and "
+                                    "VkPhysicalDeviceFeatures::wideLines is disabled, but pCreateInfos[%" PRIu32
+                                    "].pRasterizationState->lineWidth (=%f) is not 1.0.",
+                                    i, i, pCreateInfos[i].pRasterizationState->lineWidth);
                 }
             }
 
             for (size_t j = 0; j < pCreateInfos[i].stageCount; j++) {
-                skip |= validate_string(device_data->report_data, "vkCreateGraphicsPipelines",
+                skip |= validate_string("vkCreateGraphicsPipelines",
                                         ParameterName("pCreateInfos[%i].pStages[%i].pName", ParameterName::IndexVector{i, j}),
                                         "VUID-VkGraphicsPipelineCreateInfo-pStages-parameter", pCreateInfos[i].pStages[j].pName);
             }
@@ -2339,30 +1723,27 @@
     return skip;
 }
 
-bool pv_vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                 const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
-                                 VkPipeline *pPipelines) {
+bool StatelessValidation::manual_PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache,
+                                                                       uint32_t createInfoCount,
+                                                                       const VkComputePipelineCreateInfo *pCreateInfos,
+                                                                       const VkAllocationCallbacks *pAllocator,
+                                                                       VkPipeline *pPipelines) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
     for (uint32_t i = 0; i < createInfoCount; i++) {
-        skip |= validate_string(device_data->report_data, "vkCreateComputePipelines",
+        skip |= validate_string("vkCreateComputePipelines",
                                 ParameterName("pCreateInfos[%i].stage.pName", ParameterName::IndexVector{i}),
                                 "VUID-VkPipelineShaderStageCreateInfo-pName-parameter", pCreateInfos[i].stage.pName);
     }
-
     return skip;
 }
 
-bool pv_vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                        VkSampler *pSampler) {
+bool StatelessValidation::manual_PreCallValidateCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
+                                                              const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
     if (pCreateInfo != nullptr) {
-        const auto &features = device_data->physical_device_features;
-        const auto &limits = device_data->device_limits;
+        const auto &features = physical_device_features;
+        const auto &limits = device_limits;
 
         if (pCreateInfo->anisotropyEnable == VK_TRUE) {
             if (!in_inclusive_range(pCreateInfo->maxAnisotropy, 1.0F, limits.maxSamplerAnisotropy)) {
@@ -2432,9 +1813,8 @@
 
         // If compareEnable is VK_TRUE, compareOp must be a valid VkCompareOp value
         if (pCreateInfo->compareEnable == VK_TRUE) {
-            skip |=
-                validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->compareOp", "VkCompareOp", AllVkCompareOpEnums,
-                                     pCreateInfo->compareOp, "VUID-VkSamplerCreateInfo-compareEnable-01080");
+            skip |= validate_ranged_enum("vkCreateSampler", "pCreateInfo->compareOp", "VkCompareOp", AllVkCompareOpEnums,
+                                         pCreateInfo->compareOp, "VUID-VkSamplerCreateInfo-compareEnable-01080");
         }
 
         // If any of addressModeU, addressModeV or addressModeW are VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, borderColor must be a
@@ -2442,14 +1822,13 @@
         if ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) ||
             (pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) ||
             (pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)) {
-            skip |= validate_ranged_enum(report_data, "vkCreateSampler", "pCreateInfo->borderColor", "VkBorderColor",
-                                         AllVkBorderColorEnums, pCreateInfo->borderColor,
-                                         "VUID-VkSamplerCreateInfo-addressModeU-01078");
+            skip |= validate_ranged_enum("vkCreateSampler", "pCreateInfo->borderColor", "VkBorderColor", AllVkBorderColorEnums,
+                                         pCreateInfo->borderColor, "VUID-VkSamplerCreateInfo-addressModeU-01078");
         }
 
         // If any of addressModeU, addressModeV or addressModeW are VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, the
         // VK_KHR_sampler_mirror_clamp_to_edge extension must be enabled
-        if (!device_data->extensions.vk_khr_sampler_mirror_clamp_to_edge &&
+        if (!device_extensions.vk_khr_sampler_mirror_clamp_to_edge &&
             ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) ||
              (pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) ||
              (pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE))) {
@@ -2461,7 +1840,7 @@
         }
 
         // Checks for the IMG cubic filtering extension
-        if (device_data->extensions.vk_img_filter_cubic) {
+        if (device_extensions.vk_img_filter_cubic) {
             if ((pCreateInfo->anisotropyEnable == VK_TRUE) &&
                 ((pCreateInfo->minFilter == VK_FILTER_CUBIC_IMG) || (pCreateInfo->magFilter == VK_FILTER_CUBIC_IMG))) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -2475,11 +1854,11 @@
     return skip;
 }
 
-bool pv_vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
-                                    const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
+bool StatelessValidation::manual_PreCallValidateCreateDescriptorSetLayout(VkDevice device,
+                                                                          const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                                          const VkAllocationCallbacks *pAllocator,
+                                                                          VkDescriptorSetLayout *pSetLayout) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
     // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
     if ((pCreateInfo != nullptr) && (pCreateInfo->pBindings != nullptr)) {
@@ -2516,30 +1895,24 @@
             }
         }
     }
-
     return skip;
 }
 
-bool pv_vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
-                             const VkDescriptorSet *pDescriptorSets) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
+bool StatelessValidation::manual_PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool,
+                                                                   uint32_t descriptorSetCount,
+                                                                   const VkDescriptorSet *pDescriptorSets) {
     // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
     // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
     // validate_array()
-    skip |= validate_array(report_data, "vkFreeDescriptorSets", "descriptorSetCount", "pDescriptorSets", descriptorSetCount,
-                           &pDescriptorSets, true, true, kVUIDUndefined, kVUIDUndefined);
-    return skip;
+    return validate_array("vkFreeDescriptorSets", "descriptorSetCount", "pDescriptorSets", descriptorSetCount, &pDescriptorSets,
+                          true, true, kVUIDUndefined, kVUIDUndefined);
 }
 
-bool pv_vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
-                               uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
+bool StatelessValidation::manual_PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                                                     const VkWriteDescriptorSet *pDescriptorWrites,
+                                                                     uint32_t descriptorCopyCount,
+                                                                     const VkCopyDescriptorSet *pDescriptorCopies) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
     // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
     if (pDescriptorWrites != NULL) {
         for (uint32_t i = 0; i < descriptorWriteCount; ++i) {
@@ -2552,7 +1925,7 @@
             }
 
             // dstSet must be a valid VkDescriptorSet handle
-            skip |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
+            skip |= validate_required_handle("vkUpdateDescriptorSets",
                                              ParameterName("pDescriptorWrites[%i].dstSet", ParameterName::IndexVector{i}),
                                              pDescriptorWrites[i].dstSet);
 
@@ -2578,11 +1951,11 @@
                     // members of any given element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively
                     for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount;
                          ++descriptor_index) {
-                        skip |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
+                        skip |= validate_required_handle("vkUpdateDescriptorSets",
                                                          ParameterName("pDescriptorWrites[%i].pImageInfo[%i].imageView",
                                                                        ParameterName::IndexVector{i, descriptor_index}),
                                                          pDescriptorWrites[i].pImageInfo[descriptor_index].imageView);
-                        skip |= validate_ranged_enum(report_data, "vkUpdateDescriptorSets",
+                        skip |= validate_ranged_enum("vkUpdateDescriptorSets",
                                                      ParameterName("pDescriptorWrites[%i].pImageInfo[%i].imageLayout",
                                                                    ParameterName::IndexVector{i, descriptor_index}),
                                                      "VkImageLayout", AllVkImageLayoutEnums,
@@ -2606,7 +1979,7 @@
                                     i, i);
                 } else {
                     for (uint32_t descriptorIndex = 0; descriptorIndex < pDescriptorWrites[i].descriptorCount; ++descriptorIndex) {
-                        skip |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
+                        skip |= validate_required_handle("vkUpdateDescriptorSets",
                                                          ParameterName("pDescriptorWrites[%i].pBufferInfo[%i].buffer",
                                                                        ParameterName::IndexVector{i, descriptorIndex}),
                                                          pDescriptorWrites[i].pBufferInfo[descriptorIndex].buffer);
@@ -2626,7 +1999,7 @@
                 } else {
                     for (uint32_t descriptor_index = 0; descriptor_index < pDescriptorWrites[i].descriptorCount;
                          ++descriptor_index) {
-                        skip |= validate_required_handle(report_data, "vkUpdateDescriptorSets",
+                        skip |= validate_required_handle("vkUpdateDescriptorSets",
                                                          ParameterName("pDescriptorWrites[%i].pTexelBufferView[%i]",
                                                                        ParameterName::IndexVector{i, descriptor_index}),
                                                          pDescriptorWrites[i].pTexelBufferView[descriptor_index]);
@@ -2636,14 +2009,13 @@
 
             if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
                 (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)) {
-                VkDeviceSize uniformAlignment = device_data->device_limits.minUniformBufferOffsetAlignment;
+                VkDeviceSize uniformAlignment = device_limits.minUniformBufferOffsetAlignment;
                 for (uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) {
                     if (pDescriptorWrites[i].pBufferInfo != NULL) {
                         if (SafeModulo(pDescriptorWrites[i].pBufferInfo[j].offset, uniformAlignment) != 0) {
                             skip |=
-                                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
-                                        "VUID-VkWriteDescriptorSet-descriptorType-00327",
+                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                                        0, "VUID-VkWriteDescriptorSet-descriptorType-00327",
                                         "vkUpdateDescriptorSets(): pDescriptorWrites[%d].pBufferInfo[%d].offset (0x%" PRIxLEAST64
                                         ") must be a multiple of device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
                                         i, j, pDescriptorWrites[i].pBufferInfo[j].offset, uniformAlignment);
@@ -2652,14 +2024,13 @@
                 }
             } else if ((pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
                        (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
-                VkDeviceSize storageAlignment = device_data->device_limits.minStorageBufferOffsetAlignment;
+                VkDeviceSize storageAlignment = device_limits.minStorageBufferOffsetAlignment;
                 for (uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) {
                     if (pDescriptorWrites[i].pBufferInfo != NULL) {
                         if (SafeModulo(pDescriptorWrites[i].pBufferInfo[j].offset, storageAlignment) != 0) {
                             skip |=
-                                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
-                                        "VUID-VkWriteDescriptorSet-descriptorType-00328",
+                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                                        0, "VUID-VkWriteDescriptorSet-descriptorType-00328",
                                         "vkUpdateDescriptorSets(): pDescriptorWrites[%d].pBufferInfo[%d].offset (0x%" PRIxLEAST64
                                         ") must be a multiple of device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
                                         i, j, pDescriptorWrites[i].pBufferInfo[j].offset, storageAlignment);
@@ -2672,114 +2043,71 @@
     return skip;
 }
 
-template <typename RenderPassCreateInfoGeneric>
-bool pv_CreateRenderPassGeneric(VkDevice device, const RenderPassCreateInfoGeneric *pCreateInfo,
-                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
-                                RenderPassCreateVersion rp_version) {
+bool StatelessValidation::manual_PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                                 const VkAllocationCallbacks *pAllocator,
+                                                                 VkRenderPass *pRenderPass) {
+    return CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_1);
+}
+
+bool StatelessValidation::manual_PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                                                     const VkAllocationCallbacks *pAllocator,
+                                                                     VkRenderPass *pRenderPass) {
+    return CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_2);
+}
+
+bool StatelessValidation::manual_PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool,
+                                                                   uint32_t commandBufferCount,
+                                                                   const VkCommandBuffer *pCommandBuffers) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    uint32_t max_color_attachments = device_data->device_limits.maxColorAttachments;
-    bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
-    const char *vuid;
-
-    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
-        if (pCreateInfo->pAttachments[i].format == VK_FORMAT_UNDEFINED) {
-            std::stringstream ss;
-            ss << (use_rp2 ? "vkCreateRenderPass2KHR" : "vkCreateRenderPass") << ": pCreateInfo->pAttachments[" << i
-               << "].format is VK_FORMAT_UNDEFINED. ";
-            vuid = use_rp2 ? "VUID-VkAttachmentDescription2KHR-format-parameter" : "VUID-VkAttachmentDescription-format-parameter";
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            vuid, "%s", ss.str().c_str());
-        }
-        if (pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
-            pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
-            vuid =
-                use_rp2 ? "VUID-VkAttachmentDescription2KHR-finalLayout-03061" : "VUID-VkAttachmentDescription-finalLayout-00843";
-            skip |=
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
-                        "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or "
-                        "VK_IMAGE_LAYOUT_PREINITIALIZED.",
-                        i);
-        }
-    }
-
-    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
-        if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) {
-            vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063"
-                           : "VUID-VkSubpassDescription-colorAttachmentCount-00845";
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                            vuid, "Cannot create a render pass with %d color attachments. Max is %d.",
-                            pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments);
-        }
-    }
-    return skip;
-}
-
-bool pv_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                           VkRenderPass *pRenderPass) {
-    return pv_CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_1);
-}
-
-bool pv_vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                               const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
-    return pv_CreateRenderPassGeneric(device, pCreateInfo, pAllocator, pRenderPass, RENDER_PASS_VERSION_2);
-}
-
-bool pv_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
-                             const VkCommandBuffer *pCommandBuffers) {
-    bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
     // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
     // This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
     // validate_array()
-    skip |= validate_array(report_data, "vkFreeCommandBuffers", "commandBufferCount", "pCommandBuffers", commandBufferCount,
-                           &pCommandBuffers, true, true, kVUIDUndefined, kVUIDUndefined);
+    skip |= validate_array("vkFreeCommandBuffers", "commandBufferCount", "pCommandBuffers", commandBufferCount, &pCommandBuffers,
+                           true, true, kVUIDUndefined, kVUIDUndefined);
     return skip;
 }
 
-bool pv_vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
+bool StatelessValidation::manual_PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer,
+                                                                   const VkCommandBufferBeginInfo *pBeginInfo) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
     const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
 
     // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
     // TODO: pBeginInfo->pInheritanceInfo must not be NULL if commandBuffer is a secondary command buffer
-    skip |= validate_struct_type(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo",
+    skip |= validate_struct_type("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo",
                                  "VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO", pBeginInfo->pInheritanceInfo,
                                  VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, false,
                                  "VUID_vkBeginCommandBuffer-pBeginInfo-parameter", "VUID_VkCommandBufferBeginInfo-sType-sType");
 
     if (pBeginInfo->pInheritanceInfo != NULL) {
-        skip |= validate_struct_pnext(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pNext", NULL,
-                                      pBeginInfo->pInheritanceInfo->pNext, 0, NULL, GeneratedHeaderVersion,
+        skip |= validate_struct_pnext("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pNext", NULL,
+                                      pBeginInfo->pInheritanceInfo->pNext, 0, NULL, GeneratedVulkanHeaderVersion,
                                       "VUID-VkCommandBufferBeginInfo-pNext-pNext");
 
-        skip |= validate_bool32(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->occlusionQueryEnable",
+        skip |= validate_bool32("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->occlusionQueryEnable",
                                 pBeginInfo->pInheritanceInfo->occlusionQueryEnable);
 
         // TODO: This only needs to be validated when the inherited queries feature is enabled
-        // skip |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags",
+        // skip |= validate_flags("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags",
         // "VkQueryControlFlagBits", AllVkQueryControlFlagBits, pBeginInfo->pInheritanceInfo->queryFlags, false);
 
         // TODO: This must be 0 if the pipeline statistics queries feature is not enabled
-        skip |= validate_flags(report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pipelineStatistics",
+        skip |= validate_flags("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->pipelineStatistics",
                                "VkQueryPipelineStatisticFlagBits", AllVkQueryPipelineStatisticFlagBits,
                                pBeginInfo->pInheritanceInfo->pipelineStatistics, false, false, kVUIDUndefined);
     }
 
     if (pInfo != NULL) {
-        if ((device_data->physical_device_features.inheritedQueries == VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE)) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        if ((physical_device_features.inheritedQueries == VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056",
                             "Cannot set inherited occlusionQueryEnable in vkBeginCommandBuffer() when device does not support "
                             "inheritedQueries.");
         }
-        if ((device_data->physical_device_features.inheritedQueries != VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE)) {
-            skip |= validate_flags(device_data->report_data, "vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags",
-                                   "VkQueryControlFlagBits", AllVkQueryControlFlagBits, pInfo->queryFlags, false, false,
+        if ((physical_device_features.inheritedQueries != VK_FALSE) && (pInfo->occlusionQueryEnable != VK_FALSE)) {
+            skip |= validate_flags("vkBeginCommandBuffer", "pBeginInfo->pInheritanceInfo->queryFlags", "VkQueryControlFlagBits",
+                                   AllVkQueryControlFlagBits, pInfo->queryFlags, false, false,
                                    "VUID-VkCommandBufferInheritanceInfo-queryFlags-00057");
         }
     }
@@ -2787,54 +2115,52 @@
     return skip;
 }
 
-bool pv_vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
-                         const VkViewport *pViewports) {
+bool StatelessValidation::manual_PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                               uint32_t viewportCount, const VkViewport *pViewports) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
-    if (!device_data->physical_device_features.multiViewport) {
+    if (!physical_device_features.multiViewport) {
         if (firstViewport != 0) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetViewport-firstViewport-01224",
                             "vkCmdSetViewport: The multiViewport feature is disabled, but firstViewport (=%" PRIu32 ") is not 0.",
                             firstViewport);
         }
         if (viewportCount > 1) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetViewport-viewportCount-01225",
                             "vkCmdSetViewport: The multiViewport feature is disabled, but viewportCount (=%" PRIu32 ") is not 1.",
                             viewportCount);
         }
     } else {  // multiViewport enabled
         const uint64_t sum = static_cast<uint64_t>(firstViewport) + static_cast<uint64_t>(viewportCount);
-        if (sum > device_data->device_limits.maxViewports) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        if (sum > device_limits.maxViewports) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetViewport-firstViewport-01223",
                             "vkCmdSetViewport: firstViewport + viewportCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
                             ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                            firstViewport, viewportCount, sum, device_data->device_limits.maxViewports);
+                            firstViewport, viewportCount, sum, device_limits.maxViewports);
         }
     }
 
     if (pViewports) {
         for (uint32_t viewport_i = 0; viewport_i < viewportCount; ++viewport_i) {
             const auto &viewport = pViewports[viewport_i];  // will crash on invalid ptr
-            const char fn_name[] = "vkCmdSetViewport";
-            const std::string param_name = "pViewports[" + std::to_string(viewport_i) + "]";
-            skip |= pv_VkViewport(device_data, viewport, fn_name, param_name.c_str(),
-                                  VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer));
+            const char *fn_name = "vkCmdSetViewport";
+            skip |= manual_PreCallValidateViewport(viewport, fn_name,
+                                                   ParameterName("pViewports[%i]", ParameterName::IndexVector{viewport_i}),
+                                                   VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer));
         }
     }
 
     return skip;
 }
 
-bool pv_vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) {
+bool StatelessValidation::manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor,
+                                                              uint32_t scissorCount, const VkRect2D *pScissors) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
-    if (!device_data->physical_device_features.multiViewport) {
+    if (!physical_device_features.multiViewport) {
         if (firstScissor != 0) {
             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetScissor-firstScissor-00593",
@@ -2849,12 +2175,12 @@
         }
     } else {  // multiViewport enabled
         const uint64_t sum = static_cast<uint64_t>(firstScissor) + static_cast<uint64_t>(scissorCount);
-        if (sum > device_data->device_limits.maxViewports) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        if (sum > device_limits.maxViewports) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetScissor-firstScissor-00592",
                             "vkCmdSetScissor: firstScissor + scissorCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
                             ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                            firstScissor, scissorCount, sum, device_data->device_limits.maxViewports);
+                            firstScissor, scissorCount, sum, device_limits.maxViewports);
         }
     }
 
@@ -2899,12 +2225,10 @@
     return skip;
 }
 
-bool pv_vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
+bool StatelessValidation::manual_PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
-    if (!device_data->physical_device_features.wideLines && (lineWidth != 1.0f)) {
+    if (!physical_device_features.wideLines && (lineWidth != 1.0f)) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetLineWidth-lineWidth-00788",
                         "VkPhysicalDeviceFeatures::wideLines is disabled, but lineWidth (=%f) is not 1.0.", lineWidth);
@@ -2913,72 +2237,70 @@
     return skip;
 }
 
-bool pv_vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex,
-                  uint32_t firstInstance) {
+bool StatelessValidation::manual_PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
+                                                        uint32_t firstVertex, uint32_t firstInstance) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
     if (vertexCount == 0) {
         // TODO: Verify against Valid Usage section. I don't see a non-zero vertexCount listed, may need to add that and make
         // this an error or leave as is.
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         kVUID_PVError_RequiredParameter, "vkCmdDraw parameter, uint32_t vertexCount, is 0");
     }
 
     if (instanceCount == 0) {
         // TODO: Verify against Valid Usage section. I don't see a non-zero instanceCount listed, may need to add that and make
         // this an error or leave as is.
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         kVUID_PVError_RequiredParameter, "vkCmdDraw parameter, uint32_t instanceCount, is 0");
     }
     return skip;
 }
 
-bool pv_vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
+bool StatelessValidation::manual_PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                                uint32_t count, uint32_t stride) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
-    if (!device_data->physical_device_features.multiDrawIndirect && ((count > 1))) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+    if (!physical_device_features.multiDrawIndirect && ((count > 1))) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         kVUID_PVError_DeviceFeature,
                         "CmdDrawIndirect(): Device feature multiDrawIndirect disabled: count must be 0 or 1 but is %d", count);
     }
     return skip;
 }
 
-bool pv_vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
-                                 uint32_t stride) {
+bool StatelessValidation::manual_PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer,
+                                                                       VkDeviceSize offset, uint32_t count, uint32_t stride) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    if (!device_data->physical_device_features.multiDrawIndirect && ((count > 1))) {
-        skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUID_PVError_DeviceFeature,
-                    "CmdDrawIndexedIndirect(): Device feature multiDrawIndirect disabled: count must be 0 or 1 but is %d", count);
+    if (!physical_device_features.multiDrawIndirect && ((count > 1))) {
+        skip |= log_msg(
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_PVError_DeviceFeature,
+            "CmdDrawIndexedIndirect(): Device feature multiDrawIndirect disabled: count must be 0 or 1 but is %d", count);
     }
     return skip;
 }
 
-bool pv_vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
-                       VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
+bool StatelessValidation::manual_PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage,
+                                                             VkImageLayout srcImageLayout, VkImage dstImage,
+                                                             VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                             const VkImageCopy *pRegions) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     VkImageAspectFlags legal_aspect_flags =
         VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT;
-    if (device_data->extensions.vk_khr_sampler_ycbcr_conversion) {
+    if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
         legal_aspect_flags |= (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     }
 
     if (pRegions != nullptr) {
         if ((pRegions->srcSubresource.aspectMask & legal_aspect_flags) == 0) {
             skip |= log_msg(
-                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkImageSubresourceLayers-aspectMask-parameter",
                 "vkCmdCopyImage() parameter, VkImageAspect pRegions->srcSubresource.aspectMask, is an unrecognized enumerator.");
         }
         if ((pRegions->dstSubresource.aspectMask & legal_aspect_flags) == 0) {
             skip |= log_msg(
-                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 "VUID-VkImageSubresourceLayers-aspectMask-parameter",
                 "vkCmdCopyImage() parameter, VkImageAspect pRegions->dstSubresource.aspectMask, is an unrecognized enumerator.");
         }
@@ -2986,27 +2308,28 @@
     return skip;
 }
 
-bool pv_vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
-                       VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
+bool StatelessValidation::manual_PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage,
+                                                             VkImageLayout srcImageLayout, VkImage dstImage,
+                                                             VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                             const VkImageBlit *pRegions, VkFilter filter) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     VkImageAspectFlags legal_aspect_flags =
         VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT;
-    if (device_data->extensions.vk_khr_sampler_ycbcr_conversion) {
+    if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
         legal_aspect_flags |= (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     }
 
     if (pRegions != nullptr) {
         if ((pRegions->srcSubresource.aspectMask & legal_aspect_flags) == 0) {
             skip |= log_msg(
-                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 kVUID_PVError_UnrecognizedValue,
                 "vkCmdBlitImage() parameter, VkImageAspect pRegions->srcSubresource.aspectMask, is an unrecognized enumerator");
         }
         if ((pRegions->dstSubresource.aspectMask & legal_aspect_flags) == 0) {
             skip |= log_msg(
-                device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                 kVUID_PVError_UnrecognizedValue,
                 "vkCmdBlitImage() parameter, VkImageAspect pRegions->dstSubresource.aspectMask, is an unrecognized enumerator");
         }
@@ -3014,20 +2337,20 @@
     return skip;
 }
 
-bool pv_vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout,
-                               uint32_t regionCount, const VkBufferImageCopy *pRegions) {
+bool StatelessValidation::manual_PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
+                                                                     VkImage dstImage, VkImageLayout dstImageLayout,
+                                                                     uint32_t regionCount, const VkBufferImageCopy *pRegions) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     VkImageAspectFlags legal_aspect_flags =
         VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT;
-    if (device_data->extensions.vk_khr_sampler_ycbcr_conversion) {
+    if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
         legal_aspect_flags |= (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     }
 
     if (pRegions != nullptr) {
         if ((pRegions->imageSubresource.aspectMask & legal_aspect_flags) == 0) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             kVUID_PVError_UnrecognizedValue,
                             "vkCmdCopyBufferToImage() parameter, VkImageAspect pRegions->imageSubresource.aspectMask, is an "
                             "unrecognized enumerator");
@@ -3036,20 +2359,20 @@
     return skip;
 }
 
-bool pv_vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer,
-                               uint32_t regionCount, const VkBufferImageCopy *pRegions) {
+bool StatelessValidation::manual_PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
+                                                                     VkImageLayout srcImageLayout, VkBuffer dstBuffer,
+                                                                     uint32_t regionCount, const VkBufferImageCopy *pRegions) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     VkImageAspectFlags legal_aspect_flags =
         VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT;
-    if (device_data->extensions.vk_khr_sampler_ycbcr_conversion) {
+    if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
         legal_aspect_flags |= (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     }
 
     if (pRegions != nullptr) {
         if ((pRegions->imageSubresource.aspectMask & legal_aspect_flags) == 0) {
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                     kVUID_PVError_UnrecognizedValue,
                     "vkCmdCopyImageToBuffer parameter, VkImageAspect pRegions->imageSubresource.aspectMask, is an unrecognized "
                     "enumerator");
@@ -3058,41 +2381,39 @@
     return skip;
 }
 
-bool pv_vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize,
-                          const void *pData) {
+bool StatelessValidation::manual_PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
+                                                                VkDeviceSize dstOffset, VkDeviceSize dataSize, const void *pData) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     if (dstOffset & 3) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-vkCmdUpdateBuffer-dstOffset-00036",
                         "vkCmdUpdateBuffer() parameter, VkDeviceSize dstOffset (0x%" PRIxLEAST64 "), is not a multiple of 4.",
                         dstOffset);
     }
 
     if ((dataSize <= 0) || (dataSize > 65536)) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-vkCmdUpdateBuffer-dataSize-00037",
                         "vkCmdUpdateBuffer() parameter, VkDeviceSize dataSize (0x%" PRIxLEAST64
                         "), must be greater than zero and less than or equal to 65536.",
                         dataSize);
     } else if (dataSize & 3) {
         skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                     "VUID-vkCmdUpdateBuffer-dataSize-00038",
                     "vkCmdUpdateBuffer() parameter, VkDeviceSize dataSize (0x%" PRIxLEAST64 "), is not a multiple of 4.", dataSize);
     }
     return skip;
 }
 
-bool pv_vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size,
-                        uint32_t data) {
+bool StatelessValidation::manual_PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
+                                                              VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
     if (dstOffset & 3) {
         skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                     "VUID-vkCmdFillBuffer-dstOffset-00025",
                     "vkCmdFillBuffer() parameter, VkDeviceSize dstOffset (0x%" PRIxLEAST64 "), is not a multiple of 4.", dstOffset);
     }
@@ -3100,11 +2421,11 @@
     if (size != VK_WHOLE_SIZE) {
         if (size <= 0) {
             skip |=
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-vkCmdFillBuffer-size-00026",
                         "vkCmdFillBuffer() parameter, VkDeviceSize size (0x%" PRIxLEAST64 "), must be greater than zero.", size);
         } else if (size & 3) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                             "VUID-vkCmdFillBuffer-size-00028",
                             "vkCmdFillBuffer() parameter, VkDeviceSize size (0x%" PRIxLEAST64 "), is not a multiple of 4.", size);
         }
@@ -3112,57 +2433,12 @@
     return skip;
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                      VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
-        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
-
-    return VK_ERROR_LAYER_NOT_PRESENT;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
-                                                                    uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
-    // Parameter_validation does not have any physical device extensions
-    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
-        return util_GetExtensionProperties(0, NULL, pPropertyCount, pProperties);
-
-    instance_layer_data *local_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    bool skip = validate_array(local_data->report_data, "vkEnumerateDeviceExtensionProperties", "pPropertyCount", "pProperties",
-                               pPropertyCount, &pProperties, true, false, false, kVUIDUndefined,
-                               "VUID-vkEnumerateDeviceExtensionProperties-pProperties-parameter");
-    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
-
-    return local_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pPropertyCount, pProperties);
-}
-
-static bool require_device_extension(layer_data *device_data, bool flag, char const *function_name, char const *extension_name) {
-    if (!flag) {
-        return log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                       kVUID_PVError_ExtensionNotEnabled,
-                       "%s() called even though the %s extension was not enabled for this VkDevice.", function_name,
-                       extension_name);
-    }
-
-    return false;
-}
-
-bool pv_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                             VkSwapchainKHR *pSwapchain) {
+bool StatelessValidation::manual_PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                                                   const VkAllocationCallbacks *pAllocator,
+                                                                   VkSwapchainKHR *pSwapchain) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
 
-    const LogMiscParams log_misc{report_data, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, VK_NULL_HANDLE,
-                                 "vkCreateSwapchainKHR"};
+    const LogMiscParams log_misc{VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, VK_NULL_HANDLE, "vkCreateSwapchainKHR"};
 
     if (pCreateInfo != nullptr) {
         // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
@@ -3183,10 +2459,6 @@
                                 "vkCreateSwapchainKHR(): if pCreateInfo->imageSharingMode is VK_SHARING_MODE_CONCURRENT, "
                                 "pCreateInfo->pQueueFamilyIndices must be a pointer to an array of "
                                 "pCreateInfo->queueFamilyIndexCount uint32_t values.");
-            } else {
-                skip |= ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
-                                              "vkCreateSwapchainKHR", "pCreateInfo->pQueueFamilyIndices",
-                                              kVUID_PVError_InvalidUsage, kVUID_PVError_InvalidUsage, false);
             }
         }
 
@@ -3197,31 +2469,29 @@
     return skip;
 }
 
-bool pv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
+bool StatelessValidation::manual_PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
 
     if (pPresentInfo && pPresentInfo->pNext) {
         const auto *present_regions = lvl_find_in_chain<VkPresentRegionsKHR>(pPresentInfo->pNext);
         if (present_regions) {
             // TODO: This and all other pNext extension dependencies should be added to code-generation
-            skip |= require_device_extension(device_data, device_data->extensions.vk_khr_incremental_present, "vkQueuePresentKHR",
+            skip |= require_device_extension(device_extensions.vk_khr_incremental_present, "vkQueuePresentKHR",
                                              VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
             if (present_regions->swapchainCount != pPresentInfo->swapchainCount) {
-                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                                 kVUID_PVError_InvalidUsage,
                                 "QueuePresentKHR(): pPresentInfo->swapchainCount has a value of %i but VkPresentRegionsKHR "
                                 "extension swapchainCount is %i. These values must be equal.",
                                 pPresentInfo->swapchainCount, present_regions->swapchainCount);
             }
-            skip |=
-                validate_struct_pnext(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pNext", NULL,
-                                      present_regions->pNext, 0, NULL, GeneratedHeaderVersion, "VUID-VkPresentInfoKHR-pNext-pNext");
-            skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->swapchainCount",
-                                   "pCreateInfo->pNext->pRegions", present_regions->swapchainCount, &present_regions->pRegions,
-                                   true, false, kVUIDUndefined, kVUIDUndefined);
+            skip |= validate_struct_pnext("QueuePresentKHR", "pCreateInfo->pNext->pNext", NULL, present_regions->pNext, 0, NULL,
+                                          GeneratedVulkanHeaderVersion, "VUID-VkPresentInfoKHR-pNext-pNext");
+            skip |= validate_array("QueuePresentKHR", "pCreateInfo->pNext->swapchainCount", "pCreateInfo->pNext->pRegions",
+                                   present_regions->swapchainCount, &present_regions->pRegions, true, false, kVUIDUndefined,
+                                   kVUIDUndefined);
             for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
-                skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pRegions[].rectangleCount",
+                skip |= validate_array("QueuePresentKHR", "pCreateInfo->pNext->pRegions[].rectangleCount",
                                        "pCreateInfo->pNext->pRegions[].pRectangles", present_regions->pRegions[i].rectangleCount,
                                        &present_regions->pRegions[i].pRectangles, true, false, kVUIDUndefined, kVUIDUndefined);
             }
@@ -3232,13 +2502,14 @@
 }
 
 #ifdef VK_USE_PLATFORM_WIN32_KHR
-bool pv_vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
-                                const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
-    auto device_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+bool StatelessValidation::manual_PreCallValidateCreateWin32SurfaceKHR(VkInstance instance,
+                                                                      const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
+                                                                      const VkAllocationCallbacks *pAllocator,
+                                                                      VkSurfaceKHR *pSurface) {
     bool skip = false;
 
     if (pCreateInfo->hwnd == nullptr) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkWin32SurfaceCreateInfoKHR-hwnd-01308",
                         "vkCreateWin32SurfaceKHR(): hwnd must be a valid Win32 HWND but hwnd is NULL.");
     }
@@ -3247,43 +2518,30 @@
 }
 #endif  // VK_USE_PLATFORM_WIN32_KHR
 
-bool pv_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
-    auto device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (pNameInfo->pObjectName) {
-        device_data->report_data->debugObjectNameMap->insert(
-            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->object, pNameInfo->pObjectName));
-    } else {
-        device_data->report_data->debugObjectNameMap->erase(pNameInfo->object);
-    }
-    return false;
-}
-
-bool pv_vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
-                               const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
-    auto device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+bool StatelessValidation::manual_PreCallValidateCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
+                                                                     const VkAllocationCallbacks *pAllocator,
+                                                                     VkDescriptorPool *pDescriptorPool) {
     bool skip = false;
 
     if (pCreateInfo) {
         if (pCreateInfo->maxSets <= 0) {
-            skip |=
-                log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                        VK_NULL_HANDLE, "VUID-VkDescriptorPoolCreateInfo-maxSets-00301",
-                        "vkCreateDescriptorPool(): pCreateInfo->maxSets is not greater than 0.");
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
+                            VK_NULL_HANDLE, "VUID-VkDescriptorPoolCreateInfo-maxSets-00301",
+                            "vkCreateDescriptorPool(): pCreateInfo->maxSets is not greater than 0.");
         }
 
         if (pCreateInfo->pPoolSizes) {
             for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; ++i) {
                 if (pCreateInfo->pPoolSizes[i].descriptorCount <= 0) {
                     skip |= log_msg(
-                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                        VK_NULL_HANDLE, "VUID-VkDescriptorPoolSize-descriptorCount-00302",
+                        report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, VK_NULL_HANDLE,
+                        "VUID-VkDescriptorPoolSize-descriptorCount-00302",
                         "vkCreateDescriptorPool(): pCreateInfo->pPoolSizes[%" PRIu32 "].descriptorCount is not greater than 0.", i);
                 }
                 if (pCreateInfo->pPoolSizes[i].type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT &&
                     (pCreateInfo->pPoolSizes[i].descriptorCount % 4) != 0) {
-                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT, VK_NULL_HANDLE,
-                                    "VUID-VkDescriptorPoolSize-type-02218",
+                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
+                                    VK_NULL_HANDLE, "VUID-VkDescriptorPoolSize-type-02218",
                                     "vkCreateDescriptorPool(): pCreateInfo->pPoolSizes[%" PRIu32
                                     "].type is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT "
                                     " and pCreateInfo->pPoolSizes[%" PRIu32 "].descriptorCount is not a multiple of 4.",
@@ -3296,82 +2554,94 @@
     return skip;
 }
 
-bool pv_vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+bool StatelessValidation::manual_PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX,
+                                                            uint32_t groupCountY, uint32_t groupCountZ) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
 
-    if (groupCountX > device_data->device_limits.maxComputeWorkGroupCount[0]) {
+    if (groupCountX > device_limits.maxComputeWorkGroupCount[0]) {
         skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(commandBuffer), "VUID-vkCmdDispatch-groupCountX-00386",
                     "vkCmdDispatch(): groupCountX (%" PRIu32 ") exceeds device limit maxComputeWorkGroupCount[0] (%" PRIu32 ").",
-                    groupCountX, device_data->device_limits.maxComputeWorkGroupCount[0]);
+                    groupCountX, device_limits.maxComputeWorkGroupCount[0]);
     }
 
-    if (groupCountY > device_data->device_limits.maxComputeWorkGroupCount[1]) {
+    if (groupCountY > device_limits.maxComputeWorkGroupCount[1]) {
         skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(commandBuffer), "VUID-vkCmdDispatch-groupCountY-00387",
                     "vkCmdDispatch(): groupCountY (%" PRIu32 ") exceeds device limit maxComputeWorkGroupCount[1] (%" PRIu32 ").",
-                    groupCountY, device_data->device_limits.maxComputeWorkGroupCount[1]);
+                    groupCountY, device_limits.maxComputeWorkGroupCount[1]);
     }
 
-    if (groupCountZ > device_data->device_limits.maxComputeWorkGroupCount[2]) {
+    if (groupCountZ > device_limits.maxComputeWorkGroupCount[2]) {
         skip |=
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                     HandleToUint64(commandBuffer), "VUID-vkCmdDispatch-groupCountZ-00388",
                     "vkCmdDispatch(): groupCountZ (%" PRIu32 ") exceeds device limit maxComputeWorkGroupCount[2] (%" PRIu32 ").",
-                    groupCountZ, device_data->device_limits.maxComputeWorkGroupCount[2]);
+                    groupCountZ, device_limits.maxComputeWorkGroupCount[2]);
     }
 
     return skip;
 }
 
-bool pv_vkCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
-                             uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+bool StatelessValidation::manual_PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer,
+                                                                    VkDeviceSize offset) {
     bool skip = false;
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+
+    if ((offset % 4) != 0) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdDispatchIndirect-offset-00406",
+                        "vkCmdDispatchIndirect(): offset (%" PRIu64 ") must be a multiple of 4.", offset);
+    }
+    return skip;
+}
+
+bool StatelessValidation::manual_PreCallValidateCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX,
+                                                                   uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX,
+                                                                   uint32_t groupCountY, uint32_t groupCountZ) {
+    bool skip = false;
 
     // Paired if {} else if {} tests used to avoid any possible uint underflow
-    uint32_t limit = device_data->device_limits.maxComputeWorkGroupCount[0];
+    uint32_t limit = device_limits.maxComputeWorkGroupCount[0];
     if (baseGroupX >= limit) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-baseGroupX-00421",
                         "vkCmdDispatch(): baseGroupX (%" PRIu32
                         ") equals or exceeds device limit maxComputeWorkGroupCount[0] (%" PRIu32 ").",
                         baseGroupX, limit);
     } else if (groupCountX > (limit - baseGroupX)) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-groupCountX-00424",
                         "vkCmdDispatchBaseKHR(): baseGroupX (%" PRIu32 ") + groupCountX (%" PRIu32
                         ") exceeds device limit maxComputeWorkGroupCount[0] (%" PRIu32 ").",
                         baseGroupX, groupCountX, limit);
     }
 
-    limit = device_data->device_limits.maxComputeWorkGroupCount[1];
+    limit = device_limits.maxComputeWorkGroupCount[1];
     if (baseGroupY >= limit) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-baseGroupX-00422",
                         "vkCmdDispatch(): baseGroupY (%" PRIu32
                         ") equals or exceeds device limit maxComputeWorkGroupCount[1] (%" PRIu32 ").",
                         baseGroupY, limit);
     } else if (groupCountY > (limit - baseGroupY)) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-groupCountY-00425",
                         "vkCmdDispatchBaseKHR(): baseGroupY (%" PRIu32 ") + groupCountY (%" PRIu32
                         ") exceeds device limit maxComputeWorkGroupCount[1] (%" PRIu32 ").",
                         baseGroupY, groupCountY, limit);
     }
 
-    limit = device_data->device_limits.maxComputeWorkGroupCount[2];
+    limit = device_limits.maxComputeWorkGroupCount[2];
     if (baseGroupZ >= limit) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-baseGroupZ-00423",
                         "vkCmdDispatch(): baseGroupZ (%" PRIu32
                         ") equals or exceeds device limit maxComputeWorkGroupCount[2] (%" PRIu32 ").",
                         baseGroupZ, limit);
     } else if (groupCountZ > (limit - baseGroupZ)) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDispatchBase-groupCountZ-00426",
                         "vkCmdDispatchBaseKHR(): baseGroupZ (%" PRIu32 ") + groupCountZ (%" PRIu32
                         ") exceeds device limit maxComputeWorkGroupCount[2] (%" PRIu32 ").",
@@ -3381,14 +2651,13 @@
     return skip;
 }
 
-bool pv_vkCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount,
-                                   const VkRect2D *pExclusiveScissors) {
+bool StatelessValidation::manual_PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer,
+                                                                         uint32_t firstExclusiveScissor,
+                                                                         uint32_t exclusiveScissorCount,
+                                                                         const VkRect2D *pExclusiveScissors) {
     bool skip = false;
 
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
-    if (!device_data->physical_device_features.multiViewport) {
+    if (!physical_device_features.multiViewport) {
         if (firstExclusiveScissor != 0) {
             skip |=
                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -3407,21 +2676,21 @@
         }
     } else {  // multiViewport enabled
         const uint64_t sum = static_cast<uint64_t>(firstExclusiveScissor) + static_cast<uint64_t>(exclusiveScissorCount);
-        if (sum > device_data->device_limits.maxViewports) {
-            skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        if (sum > device_limits.maxViewports) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                             HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02034",
                             "vkCmdSetExclusiveScissorNV: firstExclusiveScissor + exclusiveScissorCount (=%" PRIu32 " + %" PRIu32
                             " = %" PRIu64 ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                            firstExclusiveScissor, exclusiveScissorCount, sum, device_data->device_limits.maxViewports);
+                            firstExclusiveScissor, exclusiveScissorCount, sum, device_limits.maxViewports);
         }
     }
 
-    if (firstExclusiveScissor >= device_data->device_limits.maxViewports) {
+    if (firstExclusiveScissor >= device_limits.maxViewports) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02033",
                         "vkCmdSetExclusiveScissorNV: firstExclusiveScissor (=%" PRIu32 ") must be less than maxViewports (=%" PRIu32
                         ").",
-                        firstExclusiveScissor, device_data->device_limits.maxViewports);
+                        firstExclusiveScissor, device_limits.maxViewports);
     }
 
     if (pExclusiveScissors) {
@@ -3465,14 +2734,12 @@
     return skip;
 }
 
-bool pv_vkCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
-                                             const VkShadingRatePaletteNV *pShadingRatePalettes) {
+bool StatelessValidation::manual_PreCallValidateCmdSetViewportShadingRatePaletteNV(
+    VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+    const VkShadingRatePaletteNV *pShadingRatePalettes) {
     bool skip = false;
 
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
-    if (!device_data->physical_device_features.multiViewport) {
+    if (!physical_device_features.multiViewport) {
         if (firstViewport != 0) {
             skip |=
                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -3491,33 +2758,32 @@
         }
     }
 
-    if (firstViewport >= device_data->device_limits.maxViewports) {
+    if (firstViewport >= device_limits.maxViewports) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02066",
                         "vkCmdSetViewportShadingRatePaletteNV: firstViewport (=%" PRIu32
                         ") must be less than maxViewports (=%" PRIu32 ").",
-                        firstViewport, device_data->device_limits.maxViewports);
+                        firstViewport, device_limits.maxViewports);
     }
 
     const uint64_t sum = static_cast<uint64_t>(firstViewport) + static_cast<uint64_t>(viewportCount);
-    if (sum > device_data->device_limits.maxViewports) {
-        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+    if (sum > device_limits.maxViewports) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02067",
                         "vkCmdSetViewportShadingRatePaletteNV: firstViewport + viewportCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
                         ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
-                        firstViewport, viewportCount, sum, device_data->device_limits.maxViewports);
+                        firstViewport, viewportCount, sum, device_limits.maxViewports);
     }
 
     return skip;
 }
 
-bool pv_vkCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType,
-                                    uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV *pCustomSampleOrders) {
+bool StatelessValidation::manual_PreCallValidateCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer,
+                                                                          VkCoarseSampleOrderTypeNV sampleOrderType,
+                                                                          uint32_t customSampleOrderCount,
+                                                                          const VkCoarseSampleOrderCustomNV *pCustomSampleOrders) {
     bool skip = false;
 
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = device_data->report_data;
-
     if (sampleOrderType != VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV && customSampleOrderCount != 0) {
         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdSetCoarseSampleOrderNV-sampleOrderType-02081",
@@ -3526,36 +2792,33 @@
     }
 
     for (uint32_t order_i = 0; order_i < customSampleOrderCount; ++order_i) {
-        skip |= ValidateCoarseSampleOrderCustomNV(device_data, &pCustomSampleOrders[order_i]);
+        skip |= ValidateCoarseSampleOrderCustomNV(&pCustomSampleOrders[order_i]);
     }
 
     return skip;
 }
 
-bool pv_vkCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) {
+bool StatelessValidation::manual_PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount,
+                                                                   uint32_t firstTask) {
     bool skip = false;
 
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-
-    if (taskCount > dev_data->phys_dev_ext_props.mesh_shader_props.maxDrawMeshTasksCount) {
+    if (taskCount > phys_dev_ext_props.mesh_shader_props.maxDrawMeshTasksCount) {
         skip |= log_msg(
-            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
             HandleToUint64(commandBuffer), "VUID-vkCmdDrawMeshTasksNV-taskCount-02119",
             "vkCmdDrawMeshTasksNV() parameter, uint32_t taskCount (0x%" PRIxLEAST32
             "), must be less than or equal to VkPhysicalDeviceMeshShaderPropertiesNV::maxDrawMeshTasksCount (0x%" PRIxLEAST32 ").",
-            taskCount, dev_data->phys_dev_ext_props.mesh_shader_props.maxDrawMeshTasksCount);
+            taskCount, phys_dev_ext_props.mesh_shader_props.maxDrawMeshTasksCount);
     }
 
     return skip;
 }
 
-bool pv_vkCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount,
-                                     uint32_t stride) {
+bool StatelessValidation::manual_PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer,
+                                                                           VkDeviceSize offset, uint32_t drawCount,
+                                                                           uint32_t stride) {
     bool skip = false;
 
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    debug_report_data *report_data = dev_data->report_data;
-
     if (offset & 3) {
         skip |= log_msg(
             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
@@ -3571,17 +2834,24 @@
                         stride);
     }
 
+    if (!physical_device_features.multiDrawIndirect && ((drawCount > 1))) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                        HandleToUint64(commandBuffer), "VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02147",
+                        "vkCmdDrawMeshTasksIndirectNV(): Device feature multiDrawIndirect disabled: count must be 0 or 1 but is %d",
+                        drawCount);
+    }
+
     return skip;
 }
 
-bool pv_vkCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer,
-                                          VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+bool StatelessValidation::manual_PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer,
+                                                                                VkDeviceSize offset, VkBuffer countBuffer,
+                                                                                VkDeviceSize countBufferOffset,
+                                                                                uint32_t maxDrawCount, uint32_t stride) {
     bool skip = false;
 
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-
     if (offset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawMeshTasksIndirectCountNV-offset-02180",
                         "vkCmdDrawMeshTasksIndirectCountNV() parameter, VkDeviceSize offset (0x%" PRIxLEAST64
                         "), is not a multiple of 4.",
@@ -3589,7 +2859,7 @@
     }
 
     if (countBufferOffset & 3) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawMeshTasksIndirectCountNV-countBufferOffset-02181",
                         "vkCmdDrawMeshTasksIndirectCountNV() parameter, VkDeviceSize countBufferOffset (0x%" PRIxLEAST64
                         "), is not a multiple of 4.",
@@ -3597,7 +2867,7 @@
     }
 
     if ((stride & 3) || stride < sizeof(VkDrawMeshTasksIndirectCommandNV)) {
-        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                         HandleToUint64(commandBuffer), "VUID-vkCmdDrawMeshTasksIndirectCountNV-stride-02182",
                         "vkCmdDrawMeshTasksIndirectCountNV() parameter, uint32_t stride (0x%" PRIxLEAST32
                         "), is not a multiple of 4 or smaller than sizeof (VkDrawMeshTasksIndirectCommandNV).",
@@ -3607,138 +2877,66 @@
     return skip;
 }
 
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *funcName) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (!ApiParentExtensionEnabled(funcName, device_data->extensions.device_extension_set)) {
-        return nullptr;
+bool StatelessValidation::manual_PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
+                                                                const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
+    bool skip = false;
+
+    // Validation for parameters excluded from the generated validation code due to a 'noautovalidity' tag in vk.xml
+    if (pCreateInfo != nullptr) {
+        // If queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, pipelineStatistics must be a valid combination of
+        // VkQueryPipelineStatisticFlagBits values
+        if ((pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) && (pCreateInfo->pipelineStatistics != 0) &&
+            ((pCreateInfo->pipelineStatistics & (~AllVkQueryPipelineStatisticFlagBits)) != 0)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkQueryPoolCreateInfo-queryType-00792",
+                            "vkCreateQueryPool(): if pCreateInfo->queryType is VK_QUERY_TYPE_PIPELINE_STATISTICS, "
+                            "pCreateInfo->pipelineStatistics must be a valid combination of VkQueryPipelineStatisticFlagBits "
+                            "values.");
+        }
     }
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+    return skip;
+}
+
+bool StatelessValidation::manual_PreCallValidateEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
+                                                                                   const char *pLayerName, uint32_t *pPropertyCount,
+                                                                                   VkExtensionProperties *pProperties) {
+    return validate_array("vkEnumerateDeviceExtensionProperties", "pPropertyCount", "pProperties", pPropertyCount, &pProperties,
+                          true, false, false, kVUIDUndefined, "VUID-vkEnumerateDeviceExtensionProperties-pProperties-parameter");
+}
+
+void StatelessValidation::PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                         const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
+                                                         VkResult result) {
+    if (result != VK_SUCCESS) return;
+    RecordRenderPass(*pRenderPass, pCreateInfo);
+}
+
+void StatelessValidation::PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                                             const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
+                                                             VkResult result) {
+    // Track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
+    if (result != VK_SUCCESS) return;
+    RecordRenderPass(*pRenderPass, pCreateInfo);
+}
+
+void StatelessValidation::PostCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass,
+                                                          const VkAllocationCallbacks *pAllocator) {
+    // Track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
+    std::unique_lock<std::mutex> lock(renderpass_map_mutex);
+    renderpasses_states.erase(renderPass);
+}
+
+bool StatelessValidation::manual_PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
+                                                               const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
+    bool skip = false;
+
+    if (pAllocateInfo) {
+        auto chained_prio_struct = lvl_find_in_chain<VkMemoryPriorityAllocateInfoEXT>(pAllocateInfo->pNext);
+        if (chained_prio_struct && (chained_prio_struct->priority < 0.0f || chained_prio_struct->priority > 1.0f)) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            "VUID-VkMemoryPriorityAllocateInfoEXT-priority-02602",
+                            "priority (=%f) must be between `0` and `1`, inclusive.", chained_prio_struct->priority);
+        }
     }
-    const auto &table = device_data->dispatch_table;
-    if (!table.GetDeviceProcAddr) return nullptr;
-    return table.GetDeviceProcAddr(device, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    auto &table = instance_data->dispatch_table;
-    if (!table.GetInstanceProcAddr) return nullptr;
-    return table.GetInstanceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
-    assert(instance);
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    if (!instance_data->dispatch_table.GetPhysicalDeviceProcAddr) return nullptr;
-    return instance_data->dispatch_table.GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-// If additional validation is needed outside of the generated checks, a manual routine can be added to this file
-// and the address filled in here. The autogenerated source will call these routines if the pointers are not NULL.
-void InitializeManualParameterValidationFunctionPointers() {
-    custom_functions["vkGetDeviceQueue"] = (void *)pv_vkGetDeviceQueue;
-    custom_functions["vkCreateBuffer"] = (void *)pv_vkCreateBuffer;
-    custom_functions["vkCreateImage"] = (void *)pv_vkCreateImage;
-    custom_functions["vkCreateImageView"] = (void *)pv_vkCreateImageView;
-    custom_functions["vkCreateGraphicsPipelines"] = (void *)pv_vkCreateGraphicsPipelines;
-    custom_functions["vkCreateComputePipelines"] = (void *)pv_vkCreateComputePipelines;
-    custom_functions["vkCreateSampler"] = (void *)pv_vkCreateSampler;
-    custom_functions["vkCreateDescriptorSetLayout"] = (void *)pv_vkCreateDescriptorSetLayout;
-    custom_functions["vkFreeDescriptorSets"] = (void *)pv_vkFreeDescriptorSets;
-    custom_functions["vkUpdateDescriptorSets"] = (void *)pv_vkUpdateDescriptorSets;
-    custom_functions["vkCreateRenderPass"] = (void *)pv_vkCreateRenderPass;
-    custom_functions["vkCreateRenderPass2KHR"] = (void *)pv_vkCreateRenderPass2KHR;
-    custom_functions["vkBeginCommandBuffer"] = (void *)pv_vkBeginCommandBuffer;
-    custom_functions["vkCmdSetViewport"] = (void *)pv_vkCmdSetViewport;
-    custom_functions["vkCmdSetScissor"] = (void *)pv_vkCmdSetScissor;
-    custom_functions["vkCmdSetLineWidth"] = (void *)pv_vkCmdSetLineWidth;
-    custom_functions["vkCmdDraw"] = (void *)pv_vkCmdDraw;
-    custom_functions["vkCmdDrawIndirect"] = (void *)pv_vkCmdDrawIndirect;
-    custom_functions["vkCmdDrawIndexedIndirect"] = (void *)pv_vkCmdDrawIndexedIndirect;
-    custom_functions["vkCmdCopyImage"] = (void *)pv_vkCmdCopyImage;
-    custom_functions["vkCmdBlitImage"] = (void *)pv_vkCmdBlitImage;
-    custom_functions["vkCmdCopyBufferToImage"] = (void *)pv_vkCmdCopyBufferToImage;
-    custom_functions["vkCmdCopyImageToBuffer"] = (void *)pv_vkCmdCopyImageToBuffer;
-    custom_functions["vkCmdUpdateBuffer"] = (void *)pv_vkCmdUpdateBuffer;
-    custom_functions["vkCmdFillBuffer"] = (void *)pv_vkCmdFillBuffer;
-    custom_functions["vkCreateSwapchainKHR"] = (void *)pv_vkCreateSwapchainKHR;
-    custom_functions["vkQueuePresentKHR"] = (void *)pv_vkQueuePresentKHR;
-    custom_functions["vkCreateDescriptorPool"] = (void *)pv_vkCreateDescriptorPool;
-    custom_functions["vkCmdDispatch"] = (void *)pv_vkCmdDispatch;
-    custom_functions["vkCmdDispatchBaseKHR"] = (void *)pv_vkCmdDispatchBaseKHR;
-    custom_functions["vkCmdSetExclusiveScissorNV"] = (void *)pv_vkCmdSetExclusiveScissorNV;
-    custom_functions["vkCmdSetViewportShadingRatePaletteNV"] = (void *)pv_vkCmdSetViewportShadingRatePaletteNV;
-    custom_functions["vkCmdSetCoarseSampleOrderNV"] = (void *)pv_vkCmdSetCoarseSampleOrderNV;
-    custom_functions["vkCmdDrawMeshTasksNV"] = (void *)pv_vkCmdDrawMeshTasksNV;
-    custom_functions["vkCmdDrawMeshTasksIndirectNV"] = (void *)pv_vkCmdDrawMeshTasksIndirectNV;
-    custom_functions["vkCmdDrawMeshTasksIndirectCountNV"] = (void *)pv_vkCmdDrawMeshTasksIndirectCountNV;
-}
-
-}  // namespace parameter_validation
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                                      VkExtensionProperties *pProperties) {
-    return parameter_validation::vkEnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
-                                                                                  VkLayerProperties *pProperties) {
-    return parameter_validation::vkEnumerateInstanceLayerProperties(pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                                VkLayerProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return parameter_validation::vkEnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                                                                    const char *pLayerName, uint32_t *pCount,
-                                                                                    VkExtensionProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return parameter_validation::vkEnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
-    return parameter_validation::vkGetDeviceProcAddr(dev, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    return parameter_validation::vkGetInstanceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
-                                                                                           const char *funcName) {
-    return parameter_validation::vkGetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL VKAPI_CALL
-vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
-    assert(pVersionStruct != NULL);
-    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
-
-    // Fill in the function pointers if our version is at least capable of having the structure contain them.
-    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
-        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
-        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
-        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
-    }
-
-    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        parameter_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
-    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-    }
-
-    return VK_SUCCESS;
+    return skip;
 }
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index cbd5e98..910f978 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 
 #include <cinttypes>
 #include <cassert>
+#include <chrono>
 #include <vector>
 #include <unordered_map>
 #include <string>
@@ -31,8 +32,8 @@
 #include "vk_layer_data.h"
 #include "vk_layer_extension_utils.h"
 #include "vk_layer_utils.h"
+#include "chassis.h"
 #include "core_validation.h"
-#include "core_validation_types.h"
 #include "shader_validation.h"
 #include "spirv-tools/libspirv.h"
 #include "xxhash.h"
@@ -91,7 +92,7 @@
             case spv::OpTypeReserveId:
             case spv::OpTypeQueue:
             case spv::OpTypePipe:
-            case spv::OpTypeAccelerationStructureNVX:
+            case spv::OpTypeAccelerationStructureNV:
                 def_index[insn.word(1)] = insn.offset();
                 break;
 
@@ -145,18 +146,18 @@
             return VK_SHADER_STAGE_FRAGMENT_BIT;
         case spv::ExecutionModelGLCompute:
             return VK_SHADER_STAGE_COMPUTE_BIT;
-        case spv::ExecutionModelRayGenerationNVX:
-            return VK_SHADER_STAGE_RAYGEN_BIT_NVX;
-        case spv::ExecutionModelAnyHitNVX:
-            return VK_SHADER_STAGE_ANY_HIT_BIT_NVX;
-        case spv::ExecutionModelClosestHitNVX:
-            return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX;
-        case spv::ExecutionModelMissNVX:
-            return VK_SHADER_STAGE_MISS_BIT_NVX;
-        case spv::ExecutionModelIntersectionNVX:
-            return VK_SHADER_STAGE_INTERSECTION_BIT_NVX;
-        case spv::ExecutionModelCallableNVX:
-            return VK_SHADER_STAGE_CALLABLE_BIT_NVX;
+        case spv::ExecutionModelRayGenerationNV:
+            return VK_SHADER_STAGE_RAYGEN_BIT_NV;
+        case spv::ExecutionModelAnyHitNV:
+            return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
+        case spv::ExecutionModelClosestHitNV:
+            return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
+        case spv::ExecutionModelMissNV:
+            return VK_SHADER_STAGE_MISS_BIT_NV;
+        case spv::ExecutionModelIntersectionNV:
+            return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
+        case spv::ExecutionModelCallableNV:
+            return VK_SHADER_STAGE_CALLABLE_BIT_NV;
         case spv::ExecutionModelTaskNV:
             return VK_SHADER_STAGE_TASK_BIT_NV;
         case spv::ExecutionModelMeshNV:
@@ -285,7 +286,7 @@
         case spv::OpTypeImage:
             ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
             break;
-        case spv::OpTypeAccelerationStructureNVX:
+        case spv::OpTypeAccelerationStructureNV:
             ss << "accelerationStruture";
             break;
         default:
@@ -431,6 +432,54 @@
     }
 }
 
+static unsigned GetComponentsConsumedByType(shader_module const *src, unsigned type, bool strip_array_level) {
+    auto insn = src->get_def(type);
+    assert(insn != src->end());
+
+    switch (insn.opcode()) {
+        case spv::OpTypePointer:
+            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
+            // pointers around.
+            return GetComponentsConsumedByType(src, insn.word(3), strip_array_level);
+        case spv::OpTypeStruct: {
+            uint32_t sum = 0;
+            for (uint32_t i = 2; i < insn.len(); i++) {  // i=2 to skip word(0) and word(1)=ID of struct
+                sum += GetComponentsConsumedByType(src, insn.word(i), false);
+            }
+            return sum;
+        }
+        case spv::OpTypeArray: {
+            uint32_t sum = 0;
+            for (uint32_t i = 2; i < insn.len(); i++) {
+                sum += GetComponentsConsumedByType(src, insn.word(i), false);
+            }
+            return sum;
+        }
+        case spv::OpTypeMatrix:
+            // Num locations is the dimension * element size
+            return insn.word(3) * GetComponentsConsumedByType(src, insn.word(2), false);
+        case spv::OpTypeVector: {
+            auto scalar_type = src->get_def(insn.word(2));
+            auto bit_width =
+                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
+            // One component is 32-bit
+            return (bit_width * insn.word(3) + 31) / 32;
+        }
+        case spv::OpTypeFloat: {
+            auto bit_width = insn.word(2);
+            return (bit_width + 31) / 32;
+        }
+        case spv::OpTypeInt: {
+            auto bit_width = insn.word(2);
+            return (bit_width + 31) / 32;
+        }
+        case spv::OpConstant:
+            return GetComponentsConsumedByType(src, insn.word(1), false);
+        default:
+            return 0;
+    }
+}
+
 static unsigned GetLocationsConsumedByFormat(VkFormat format) {
     switch (format) {
         case VK_FORMAT_R64G64B64A64_SFLOAT:
@@ -892,6 +941,9 @@
     auto it_a = outputs.begin();
     auto it_b = color_attachments.begin();
     bool used = false;
+    bool alphaToCoverageEnabled = pipeline->graphicsPipelineCI.pMultisampleState != NULL &&
+                                  pipeline->graphicsPipelineCI.pMultisampleState->alphaToCoverageEnable == VK_TRUE;
+    bool locationZeroHasAlpha = false;
 
     // Walk attachment list and outputs together
 
@@ -899,10 +951,16 @@
         bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
         bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
 
+        if (!a_at_end && it_a->first.first == 0 && fs->get_def(it_a->second.type_id) != fs->end() &&
+            GetComponentsConsumedByType(fs, it_a->second.type_id, false) == 4)
+            locationZeroHasAlpha = true;
+
         if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
-                            HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_OutputNotConsumed,
-                            "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
+            if (!alphaToCoverageEnabled || it_a->first.first != 0) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                                HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_OutputNotConsumed,
+                                "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
+            }
             it_a++;
         } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
             // Only complain if there are unmasked channels for this attachment. If the writemask is 0, it's acceptable for the
@@ -936,6 +994,12 @@
         }
     }
 
+    if (alphaToCoverageEnabled && !locationZeroHasAlpha) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                        HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_NoAlphaAtLocation0WithAlphaToCoverage,
+                        "fragment shader doesn't declare alpha output at location 0 even though alpha to coverage is enabled.");
+    }
+
     return skip;
 }
 
@@ -1313,8 +1377,8 @@
                 return ret;
             }
         }
-        case spv::OpTypeAccelerationStructureNVX:
-            ret.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX);
+        case spv::OpTypeAccelerationStructureNV:
+            ret.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
             return ret;
 
             // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
@@ -1355,13 +1419,12 @@
     return false;
 }
 
-static bool ValidateShaderCapabilities(layer_data *dev_data, shader_module const *src, VkShaderStageFlagBits stage,
-                                       bool has_writable_descriptor) {
+bool CoreChecks::ValidateShaderCapabilities(layer_data *dev_data, shader_module const *src, VkShaderStageFlagBits stage,
+                                            bool has_writable_descriptor) {
     bool skip = false;
 
-    auto report_data = GetReportData(dev_data);
-    auto const &features = GetEnabledFeatures(dev_data);
-    auto const &extensions = GetDeviceExtensions(dev_data);
+    auto const &features = GetEnabledFeatures();
+    auto const &extensions = GetDeviceExtensions();
 
     struct FeaturePointer {
         // Callable object to test if this feature is enabled in the given aggregate feature struct
@@ -1381,6 +1444,12 @@
             : IsEnabled([=](const DeviceFeatures &features) { return features.descriptor_indexing.*ptr; }) {}
         FeaturePointer(VkBool32 VkPhysicalDevice8BitStorageFeaturesKHR::*ptr)
             : IsEnabled([=](const DeviceFeatures &features) { return features.eight_bit_storage.*ptr; }) {}
+        FeaturePointer(VkBool32 VkPhysicalDeviceTransformFeedbackFeaturesEXT::*ptr)
+            : IsEnabled([=](const DeviceFeatures &features) { return features.transform_feedback_features.*ptr; }) {}
+        FeaturePointer(VkBool32 VkPhysicalDeviceFloat16Int8FeaturesKHR::*ptr)
+            : IsEnabled([=](const DeviceFeatures &features) { return features.float16_int8.*ptr; }) {}
+        FeaturePointer(VkBool32 VkPhysicalDeviceScalarBlockLayoutFeaturesEXT::*ptr)
+            : IsEnabled([=](const DeviceFeatures &features) { return features.scalar_block_layout_features.*ptr; }) {}
     };
 
     struct CapabilityInfo {
@@ -1457,6 +1526,12 @@
         {spv::CapabilityStorageBuffer8BitAccess , {"VkPhysicalDevice8BitStorageFeaturesKHR::storageBuffer8BitAccess", &VkPhysicalDevice8BitStorageFeaturesKHR::storageBuffer8BitAccess, &DeviceExtensions::vk_khr_8bit_storage}},
         {spv::CapabilityUniformAndStorageBuffer8BitAccess , {"VkPhysicalDevice8BitStorageFeaturesKHR::uniformAndStorageBuffer8BitAccess", &VkPhysicalDevice8BitStorageFeaturesKHR::uniformAndStorageBuffer8BitAccess, &DeviceExtensions::vk_khr_8bit_storage}},
         {spv::CapabilityStoragePushConstant8 , {"VkPhysicalDevice8BitStorageFeaturesKHR::storagePushConstant8", &VkPhysicalDevice8BitStorageFeaturesKHR::storagePushConstant8, &DeviceExtensions::vk_khr_8bit_storage}},
+
+        {spv::CapabilityTransformFeedback , { "VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback", &VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback, &DeviceExtensions::vk_ext_transform_feedback}},
+        {spv::CapabilityGeometryStreams , { "VkPhysicalDeviceTransformFeedbackFeaturesEXT::geometryStreams", &VkPhysicalDeviceTransformFeedbackFeaturesEXT::geometryStreams, &DeviceExtensions::vk_ext_transform_feedback}},
+
+        {spv::CapabilityFloat16 , {"VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderFloat16", &VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderFloat16, &DeviceExtensions::vk_khr_shader_float16_int8}},
+        {spv::CapabilityInt8 , {"VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderInt8", &VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderInt8, &DeviceExtensions::vk_khr_shader_float16_int8}},
     };
     // clang-format on
 
@@ -1508,8 +1583,16 @@
     if (has_writable_descriptor) {
         switch (stage) {
             case VK_SHADER_STAGE_COMPUTE_BIT:
+            case VK_SHADER_STAGE_RAYGEN_BIT_NV:
+            case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
+            case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
+            case VK_SHADER_STAGE_MISS_BIT_NV:
+            case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
+            case VK_SHADER_STAGE_CALLABLE_BIT_NV:
+            case VK_SHADER_STAGE_TASK_BIT_NV:
+            case VK_SHADER_STAGE_MESH_BIT_NV:
                 /* No feature requirements for writes and atomics from compute
-                 * stage */
+                 * raytracing, or mesh stages */
                 break;
             case VK_SHADER_STAGE_FRAGMENT_BIT:
                 skip |= RequireFeature(report_data, features->core.fragmentStoresAndAtomics, "fragmentStoresAndAtomics");
@@ -1524,7 +1607,228 @@
     return skip;
 }
 
-static uint32_t DescriptorTypeToReqs(shader_module const *module, uint32_t type_id) {
+static bool VariableIsBuiltIn(shader_module const *src, const uint32_t ID, std::vector<uint32_t> const &builtInBlockIDs,
+                              std::vector<uint32_t> const &builtInIDs) {
+    auto insn = src->get_def(ID);
+
+    switch (insn.opcode()) {
+        case spv::OpVariable: {
+            // First check if the variable is a "pure" built-in type, e.g. gl_ViewportIndex
+            uint32_t ID = insn.word(2);
+            for (auto builtInID : builtInIDs) {
+                if (ID == builtInID) {
+                    return true;
+                }
+            }
+
+            VariableIsBuiltIn(src, insn.word(1), builtInBlockIDs, builtInIDs);
+            break;
+        }
+        case spv::OpTypePointer:
+            VariableIsBuiltIn(src, insn.word(3), builtInBlockIDs, builtInIDs);
+            break;
+        case spv::OpTypeArray:
+            VariableIsBuiltIn(src, insn.word(2), builtInBlockIDs, builtInIDs);
+            break;
+        case spv::OpTypeStruct: {
+            uint32_t ID = insn.word(1);  // We only need to check the first member as either all will be, or none will be built-in
+            for (auto builtInBlockID : builtInBlockIDs) {
+                if (ID == builtInBlockID) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        default:
+            return false;
+    }
+
+    return false;
+}
+
+bool CoreChecks::ValidateShaderStageInputOutputLimits(layer_data *dev_data, shader_module const *src,
+                                                      VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline) {
+    if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT || pStage->stage == VK_SHADER_STAGE_ALL_GRAPHICS ||
+        pStage->stage == VK_SHADER_STAGE_ALL) {
+        return false;
+    }
+
+    bool skip = false;
+    auto const &limits = dev_data->phys_dev_props.limits;
+
+    std::vector<uint32_t> builtInBlockIDs;
+    std::vector<uint32_t> builtInIDs;
+    struct Variable {
+        uint32_t baseTypePtrID;
+        uint32_t ID;
+        uint32_t storageClass;
+    };
+    std::vector<Variable> variables;
+
+    for (auto insn : *src) {
+        switch (insn.opcode()) {
+            // Find all built-in member decorations
+            case spv::OpMemberDecorate:
+                if (insn.word(3) == spv::DecorationBuiltIn) {
+                    builtInBlockIDs.push_back(insn.word(1));
+                }
+                break;
+            // Find all built-in decorations
+            case spv::OpDecorate:
+                switch (insn.word(2)) {
+                    case spv::DecorationBlock: {
+                        uint32_t blockID = insn.word(1);
+                        for (auto builtInBlockID : builtInBlockIDs) {
+                            // Check if one of the members of the block are built-in -> the block is built-in
+                            if (blockID == builtInBlockID) {
+                                builtInIDs.push_back(blockID);
+                                break;
+                            }
+                        }
+                        break;
+                    }
+                    case spv::DecorationBuiltIn:
+                        builtInIDs.push_back(insn.word(1));
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            // Find all input and output variables
+            case spv::OpVariable: {
+                Variable var = {};
+                var.storageClass = insn.word(3);
+                if (var.storageClass == spv::StorageClassInput || var.storageClass == spv::StorageClassOutput) {
+                    var.baseTypePtrID = insn.word(1);
+                    var.ID = insn.word(2);
+                    variables.push_back(var);
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    uint32_t numCompIn = 0, numCompOut = 0;
+    for (auto &var : variables) {
+        // Check the variable's ID
+        if (VariableIsBuiltIn(src, var.ID, builtInBlockIDs, builtInIDs)) {
+            continue;
+        }
+        // Check the variable's type's ID - e.g. gl_PerVertex is made of basic types, not built-in types
+        if (VariableIsBuiltIn(src, src->get_def(var.baseTypePtrID).word(3), builtInBlockIDs, builtInIDs)) {
+            continue;
+        }
+
+        if (var.storageClass == spv::StorageClassInput) {
+            numCompIn += GetComponentsConsumedByType(src, var.baseTypePtrID, false);
+        } else {  // var.storageClass == spv::StorageClassOutput
+            numCompOut += GetComponentsConsumedByType(src, var.baseTypePtrID, false);
+        }
+    }
+
+    switch (pStage->stage) {
+        case VK_SHADER_STAGE_VERTEX_BIT:
+            if (numCompOut > limits.maxVertexOutputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Vertex shader exceeds "
+                                "VkPhysicalDeviceLimits::maxVertexOutputComponents of %u "
+                                "components by %u components",
+                                limits.maxVertexOutputComponents, numCompOut - limits.maxVertexOutputComponents);
+            }
+            break;
+
+        case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
+            if (numCompIn > limits.maxTessellationControlPerVertexInputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
+                                "VkPhysicalDeviceLimits::maxTessellationControlPerVertexInputComponents of %u "
+                                "components by %u components",
+                                limits.maxTessellationControlPerVertexInputComponents,
+                                numCompIn - limits.maxTessellationControlPerVertexInputComponents);
+            }
+            if (numCompOut > limits.maxTessellationControlPerVertexOutputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
+                                "VkPhysicalDeviceLimits::maxTessellationControlPerVertexOutputComponents of %u "
+                                "components by %u components",
+                                limits.maxTessellationControlPerVertexOutputComponents,
+                                numCompOut - limits.maxTessellationControlPerVertexOutputComponents);
+            }
+            break;
+
+        case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
+            if (numCompIn > limits.maxTessellationEvaluationInputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
+                                "VkPhysicalDeviceLimits::maxTessellationEvaluationInputComponents of %u "
+                                "components by %u components",
+                                limits.maxTessellationEvaluationInputComponents,
+                                numCompIn - limits.maxTessellationEvaluationInputComponents);
+            }
+            if (numCompOut > limits.maxTessellationEvaluationOutputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
+                                "VkPhysicalDeviceLimits::maxTessellationEvaluationOutputComponents of %u "
+                                "components by %u components",
+                                limits.maxTessellationEvaluationOutputComponents,
+                                numCompOut - limits.maxTessellationEvaluationOutputComponents);
+            }
+            break;
+
+        case VK_SHADER_STAGE_GEOMETRY_BIT:
+            if (numCompIn > limits.maxGeometryInputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
+                                "VkPhysicalDeviceLimits::maxGeometryInputComponents of %u "
+                                "components by %u components",
+                                limits.maxGeometryInputComponents, numCompIn - limits.maxGeometryInputComponents);
+            }
+            if (numCompOut > limits.maxGeometryOutputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
+                                "VkPhysicalDeviceLimits::maxGeometryOutputComponents of %u "
+                                "components by %u components",
+                                limits.maxGeometryOutputComponents, numCompOut - limits.maxGeometryOutputComponents);
+            }
+            break;
+
+        case VK_SHADER_STAGE_FRAGMENT_BIT:
+            if (numCompIn > limits.maxFragmentInputComponents) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+                                HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
+                                "Invalid Pipeline CreateInfo State: Fragment shader exceeds "
+                                "VkPhysicalDeviceLimits::maxFragmentInputComponents of %u "
+                                "components by %u components",
+                                limits.maxFragmentInputComponents, numCompIn - limits.maxFragmentInputComponents);
+            }
+            break;
+
+        case VK_SHADER_STAGE_RAYGEN_BIT_NV:
+        case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
+        case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
+        case VK_SHADER_STAGE_MISS_BIT_NV:
+        case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
+        case VK_SHADER_STAGE_CALLABLE_BIT_NV:
+        case VK_SHADER_STAGE_TASK_BIT_NV:
+        case VK_SHADER_STAGE_MESH_BIT_NV:
+            break;
+
+        default:
+            assert(false);  // This should never happen
+    }
+    return skip;
+}
+
+uint32_t DescriptorTypeToReqs(shader_module const *module, uint32_t type_id) {
     auto type = module->get_def(type_id);
 
     while (true) {
@@ -1635,8 +1939,8 @@
 //            * gl_PointSize must be written in the final geometry stage
 //        - If shaderTessellationAndGeometryPointSize feature is disabled:
 //            * gl_PointSize must NOT be written and a default of 1.0 is assumed
-bool ValidatePointListShaderState(const layer_data *dev_data, const PIPELINE_STATE *pipeline, shader_module const *src,
-                                  spirv_inst_iter entrypoint, VkShaderStageFlagBits stage) {
+bool CoreChecks::ValidatePointListShaderState(const layer_data *dev_data, const PIPELINE_STATE *pipeline, shader_module const *src,
+                                              spirv_inst_iter entrypoint, VkShaderStageFlagBits stage) {
     if (pipeline->topology_at_rasterizer != VK_PRIMITIVE_TOPOLOGY_POINT_LIST) {
         return false;
     }
@@ -1666,16 +1970,16 @@
     }
 
     if ((stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || stage == VK_SHADER_STAGE_GEOMETRY_BIT) &&
-        !GetEnabledFeatures(dev_data)->core.shaderTessellationAndGeometryPointSize) {
+        !GetEnabledFeatures()->core.shaderTessellationAndGeometryPointSize) {
         if (pointsize_written) {
-            skip |= log_msg(GetReportData(dev_data), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+            skip |= log_msg(GetReportData(), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                             HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_PointSizeBuiltInOverSpecified,
                             "Pipeline topology is set to POINT_LIST and geometry or tessellation shaders write PointSize which "
                             "is prohibited when the shaderTessellationAndGeometryPointSize feature is not enabled.");
         }
     } else if (!pointsize_written) {
         skip |=
-            log_msg(GetReportData(dev_data), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+            log_msg(GetReportData(), VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
                     HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_MissingPointSizeBuiltIn,
                     "Pipeline topology is set to POINT_LIST, but PointSize is not written to in the shader corresponding to %s.",
                     string_VkShaderStageFlagBits(stage));
@@ -1683,12 +1987,12 @@
     return skip;
 }
 
-static bool ValidatePipelineShaderStage(layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage,
-                                        PIPELINE_STATE *pipeline, shader_module const **out_module, spirv_inst_iter *out_entrypoint,
-                                        bool check_point_size) {
+bool CoreChecks::ValidatePipelineShaderStage(layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage,
+                                             PIPELINE_STATE *pipeline, shader_module const **out_module,
+                                             spirv_inst_iter *out_entrypoint, bool check_point_size) {
     bool skip = false;
-    auto module = *out_module = GetShaderModuleState(dev_data, pStage->module);
-    auto report_data = GetReportData(dev_data);
+    auto module = *out_module = GetShaderModuleState(pStage->module);
+    auto report_data = GetReportData();
 
     if (!module->has_valid_spirv) return false;
 
@@ -1712,7 +2016,7 @@
 
     // Validate shader capabilities against enabled device features
     skip |= ValidateShaderCapabilities(dev_data, module, pStage->stage, has_writable_descriptor);
-
+    skip |= ValidateShaderStageInputOutputLimits(dev_data, module, pStage, pipeline);
     skip |= ValidateSpecializationOffsets(report_data, pStage);
     skip |= ValidatePushConstantUsage(report_data, pipeline->pipeline_layout.push_constant_ranges.get(), module, accessible_ids,
                                       pStage->stage);
@@ -1874,11 +2178,11 @@
 
 // Validate that the shaders used by the given pipeline and store the active_slots
 //  that are actually used by the pipeline into pPipeline->active_slots
-bool ValidateAndCapturePipelineShaderState(layer_data *dev_data, PIPELINE_STATE *pipeline) {
+bool CoreChecks::ValidateAndCapturePipelineShaderState(layer_data *dev_data, PIPELINE_STATE *pipeline) {
     auto pCreateInfo = pipeline->graphicsPipelineCI.ptr();
     int vertex_stage = GetShaderStageId(VK_SHADER_STAGE_VERTEX_BIT);
     int fragment_stage = GetShaderStageId(VK_SHADER_STAGE_FRAGMENT_BIT);
-    auto report_data = GetReportData(dev_data);
+    auto report_data = GetReportData();
 
     shader_module const *shaders[32];
     memset(shaders, 0, sizeof(shaders));
@@ -1937,7 +2241,7 @@
     return skip;
 }
 
-bool ValidateComputePipeline(layer_data *dev_data, PIPELINE_STATE *pipeline) {
+bool CoreChecks::ValidateComputePipeline(layer_data *dev_data, PIPELINE_STATE *pipeline) {
     auto pCreateInfo = pipeline->computePipelineCI.ptr();
 
     shader_module const *module;
@@ -1946,7 +2250,7 @@
     return ValidatePipelineShaderStage(dev_data, &pCreateInfo->stage, pipeline, &module, &entrypoint, false);
 }
 
-bool ValidateRaytracingPipelineNVX(layer_data *dev_data, PIPELINE_STATE *pipeline) {
+bool CoreChecks::ValidateRayTracingPipelineNV(layer_data *dev_data, PIPELINE_STATE *pipeline) {
     auto pCreateInfo = pipeline->raytracingPipelineCI.ptr();
 
     shader_module const *module;
@@ -1966,19 +2270,21 @@
     return nullptr;
 }
 
-bool PreCallValidateCreateShaderModule(layer_data *dev_data, VkShaderModuleCreateInfo const *pCreateInfo, bool *spirv_valid) {
+bool CoreChecks::PreCallValidateCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
     bool skip = false;
     spv_result_t spv_valid = SPV_SUCCESS;
-    auto report_data = GetReportData(dev_data);
 
-    if (GetDisables(dev_data)->shader_validation) {
+    if (GetDisables()->shader_validation) {
         return false;
     }
 
-    auto have_glsl_shader = GetDeviceExtensions(dev_data)->vk_nv_glsl_shader;
+    auto have_glsl_shader = GetDeviceExtensions()->vk_nv_glsl_shader;
 
     if (!have_glsl_shader && (pCreateInfo->codeSize % 4)) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+        skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
                         "VUID-VkShaderModuleCreateInfo-pCode-01376",
                         "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ".",
                         pCreateInfo->codeSize);
@@ -1992,23 +2298,27 @@
 
         // Use SPIRV-Tools validator to try and catch any issues with the module itself
         spv_target_env spirv_environment = SPV_ENV_VULKAN_1_0;
-        if (GetApiVersion(dev_data) >= VK_API_VERSION_1_1) {
+        if (GetApiVersion() >= VK_API_VERSION_1_1) {
             spirv_environment = SPV_ENV_VULKAN_1_1;
         }
         spv_context ctx = spvContextCreate(spirv_environment);
         spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
         spv_diagnostic diag = nullptr;
         spv_validator_options options = spvValidatorOptionsCreate();
-        if (GetDeviceExtensions(dev_data)->vk_khr_relaxed_block_layout) {
+        if (GetDeviceExtensions()->vk_khr_relaxed_block_layout) {
             spvValidatorOptionsSetRelaxBlockLayout(options, true);
         }
+        if (GetDeviceExtensions()->vk_ext_scalar_block_layout &&
+            GetEnabledFeatures()->scalar_block_layout_features.scalarBlockLayout == VK_TRUE) {
+            spvValidatorOptionsSetScalarBlockLayout(options, true);
+        }
         spv_valid = spvValidateWithOptions(ctx, options, &binary, &diag);
         if (spv_valid != SPV_SUCCESS) {
             if (!have_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
-                skip |=
-                    log_msg(report_data, spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_InconsistentSpirv,
-                            "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
+                skip |= log_msg(device_data->report_data,
+                                spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_InconsistentSpirv,
+                                "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
             }
         } else {
             if (cache) {
@@ -2021,6 +2331,33 @@
         spvContextDestroy(ctx);
     }
 
-    *spirv_valid = (spv_valid == SPV_SUCCESS);
     return skip;
 }
+
+void CoreChecks::PreCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
+                                                 const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
+                                                 void *csm_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    create_shader_module_api_state *csm_state = reinterpret_cast<create_shader_module_api_state *>(csm_state_data);
+    if (GetEnables()->gpu_validation) {
+        GpuPreCallCreateShaderModule(device_data, pCreateInfo, pAllocator, pShaderModule, &csm_state->unique_shader_id,
+                                     &csm_state->instrumented_create_info, &csm_state->instrumented_pgm);
+    }
+}
+
+void CoreChecks::PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
+                                                  VkResult result, void *csm_state_data) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    if (VK_SUCCESS != result) return;
+    create_shader_module_api_state *csm_state = reinterpret_cast<create_shader_module_api_state *>(csm_state_data);
+
+    spv_target_env spirv_environment = ((GetApiVersion() >= VK_API_VERSION_1_1) ? SPV_ENV_VULKAN_1_1 : SPV_ENV_VULKAN_1_0);
+    bool is_spirv = (pCreateInfo->pCode[0] == spv::MagicNumber);
+    std::unique_ptr<shader_module> new_shader_module(
+        is_spirv ? new shader_module(pCreateInfo, *pShaderModule, spirv_environment, csm_state->unique_shader_id)
+                 : new shader_module());
+    device_data->shaderModuleMap[*pShaderModule] = std::move(new_shader_module);
+}
diff --git a/layers/shader_validation.h b/layers/shader_validation.h
index 40edd5b..230adc1 100644
--- a/layers/shader_validation.h
+++ b/layers/shader_validation.h
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2017 The Khronos Group Inc.
- * Copyright (c) 2015-2017 Valve Corporation
- * Copyright (c) 2015-2017 LunarG, Inc.
- * Copyright (C) 2015-2017 Google Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 #define VULKAN_SHADER_VALIDATION_H
 
 #include <spirv_tools_commit_id.h>
+#include "spirv-tools/optimizer.hpp"
 
 // A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
 // without the caller needing to care too much about the physical SPIRV module layout.
@@ -75,12 +76,23 @@
     std::unordered_map<unsigned, unsigned> def_index;
     bool has_valid_spirv;
     VkShaderModule vk_shader_module;
+    uint32_t gpu_validation_shader_id;
 
-    shader_module(VkShaderModuleCreateInfo const *pCreateInfo, VkShaderModule shaderModule)
-        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
+    std::vector<uint32_t> PreprocessShaderBinary(uint32_t *src_binary, size_t binary_size, spv_target_env env) {
+        spvtools::Optimizer optimizer(env);
+        optimizer.RegisterPass(spvtools::CreateFlattenDecorationPass());
+        std::vector<uint32_t> optimized_binary;
+        auto result = optimizer.Run(src_binary, binary_size / sizeof(uint32_t), &optimized_binary);
+        return (result ? optimized_binary : std::vector<uint32_t>(src_binary, src_binary + binary_size / sizeof(uint32_t)));
+    }
+
+    shader_module(VkShaderModuleCreateInfo const *pCreateInfo, VkShaderModule shaderModule, spv_target_env env,
+                  uint32_t unique_shader_id)
+        : words(PreprocessShaderBinary((uint32_t *)pCreateInfo->pCode, pCreateInfo->codeSize, env)),
           def_index(),
           has_valid_spirv(true),
-          vk_shader_module(shaderModule) {
+          vk_shader_module(shaderModule),
+          gpu_validation_shader_id(unique_shader_id) {
         BuildDefIndex();
     }
 
@@ -194,10 +206,6 @@
     }
 };
 
-bool ValidateAndCapturePipelineShaderState(layer_data *dev_data, PIPELINE_STATE *pPipeline);
-bool ValidateComputePipeline(layer_data *dev_data, PIPELINE_STATE *pPipeline);
-bool ValidateRaytracingPipelineNVX(layer_data *dev_data, PIPELINE_STATE *pipeline);
 typedef std::pair<unsigned, unsigned> descriptor_slot_t;
-bool PreCallValidateCreateShaderModule(layer_data *dev_data, VkShaderModuleCreateInfo const *pCreateInfo, bool *spirv_valid);
 
 #endif  // VULKAN_SHADER_VALIDATION_H
diff --git a/layers/stateless_validation.h b/layers/stateless_validation.h
new file mode 100644
index 0000000..977cf9b
--- /dev/null
+++ b/layers/stateless_validation.h
@@ -0,0 +1,1053 @@
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Dustin Graves <dustin@lunarg.com>
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ */
+
+#pragma once
+
+#include <bitset>
+
+#include "parameter_name.h"
+#include "vk_typemap_helper.h"
+
+// Suppress unused warning on Linux
+#if defined(__GNUC__)
+#define DECORATE_UNUSED __attribute__((unused))
+#else
+#define DECORATE_UNUSED
+#endif
+
+static const char DECORATE_UNUSED *kVUID_PVError_NONE = "UNASSIGNED-GeneralParameterError-Info";
+static const char DECORATE_UNUSED *kVUID_PVError_InvalidUsage = "UNASSIGNED-GeneralParameterError-InvalidUsage";
+static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructSType = "UNASSIGNED-GeneralParameterError-InvalidStructSType";
+static const char DECORATE_UNUSED *kVUID_PVError_InvalidStructPNext = "UNASSIGNED-GeneralParameterError-InvalidStructPNext";
+static const char DECORATE_UNUSED *kVUID_PVError_RequiredParameter = "UNASSIGNED-GeneralParameterError-RequiredParameter";
+static const char DECORATE_UNUSED *kVUID_PVError_ReservedParameter = "UNASSIGNED-GeneralParameterError-ReservedParameter";
+static const char DECORATE_UNUSED *kVUID_PVError_UnrecognizedValue = "UNASSIGNED-GeneralParameterError-UnrecognizedValue";
+static const char DECORATE_UNUSED *kVUID_PVError_DeviceLimit = "UNASSIGNED-GeneralParameterError-DeviceLimit";
+static const char DECORATE_UNUSED *kVUID_PVError_DeviceFeature = "UNASSIGNED-GeneralParameterError-DeviceFeature";
+static const char DECORATE_UNUSED *kVUID_PVError_FailureCode = "UNASSIGNED-GeneralParameterError-FailureCode";
+static const char DECORATE_UNUSED *kVUID_PVError_ExtensionNotEnabled = "UNASSIGNED-GeneralParameterError-ExtensionNotEnabled";
+
+#undef DECORATE_UNUSED
+
+extern const uint32_t GeneratedVulkanHeaderVersion;
+
+extern const VkQueryPipelineStatisticFlags AllVkQueryPipelineStatisticFlagBits;
+extern const VkColorComponentFlags AllVkColorComponentFlagBits;
+extern const VkShaderStageFlags AllVkShaderStageFlagBits;
+extern const VkQueryControlFlags AllVkQueryControlFlagBits;
+extern const VkImageUsageFlags AllVkImageUsageFlagBits;
+
+extern const std::vector<VkCompareOp> AllVkCompareOpEnums;
+extern const std::vector<VkStencilOp> AllVkStencilOpEnums;
+extern const std::vector<VkBlendFactor> AllVkBlendFactorEnums;
+extern const std::vector<VkBlendOp> AllVkBlendOpEnums;
+extern const std::vector<VkLogicOp> AllVkLogicOpEnums;
+extern const std::vector<VkBorderColor> AllVkBorderColorEnums;
+extern const std::vector<VkImageLayout> AllVkImageLayoutEnums;
+
+struct GenericHeader {
+    VkStructureType sType;
+    const void *pNext;
+};
+
+// String returned by string_VkStructureType for an unrecognized type.
+const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
+
+// String returned by string_VkResult for an unrecognized type.
+const std::string UnsupportedResultString = "Unhandled VkResult";
+
+// The base value used when computing the offset for an enumeration token value that is added by an extension.
+// When validating enumeration tokens, any value >= to this value is considered to be provided by an extension.
+// See Appendix C.10 "Assigning Extension Token Values" from the Vulkan specification
+const uint32_t ExtEnumBaseValue = 1000000000;
+
+// The value of all VK_xxx_MAX_ENUM tokens
+const uint32_t MaxEnumValue = 0x7FFFFFFF;
+
+// Misc parameters of log_msg that are likely constant per command (or low frequency change)
+struct LogMiscParams {
+    VkDebugReportObjectTypeEXT objectType;
+    uint64_t srcObject;
+    const char *api_name;
+};
+
+class StatelessValidation : public ValidationObject {
+   public:
+    VkPhysicalDeviceLimits device_limits = {};
+    VkPhysicalDeviceFeatures physical_device_features = {};
+    VkDevice device = VK_NULL_HANDLE;
+    uint32_t api_version;
+
+    // Override chassis read/write locks for this validation object
+    // This override takes a deferred lock. i.e. it is not acquired.
+    std::unique_lock<std::mutex> write_lock() { return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock); }
+
+    // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2KHR::pNext chain
+    struct DeviceExtensionProperties {
+        VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props;
+        VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props;
+    };
+    DeviceExtensionProperties phys_dev_ext_props = {};
+
+    struct SubpassesUsageStates {
+        std::unordered_set<uint32_t> subpasses_using_color_attachment;
+        std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
+    };
+
+    // Though this validation object is predominantly statless, the Framebuffer checks are greatly simplified by creating and
+    // updating a map of the renderpass usage states, and these accesses need thread protection. Use a mutex separate from the
+    // parent object's to maintain that functionality.
+    std::mutex renderpass_map_mutex;
+    std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
+
+    // Constructor for stateles validation tracking
+    // StatelessValidation() : {}
+    /**
+     * Validate a minimum value.
+     *
+     * Verify that the specified value is greater than the specified lower bound.
+     *
+     * @param api_name Name of API call being validated.
+     * @param parameter_name Name of parameter being validated.
+     * @param value Value to validate.
+     * @param lower_bound Lower bound value to use for validation.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool ValidateGreaterThan(const T value, const T lower_bound, const ParameterName &parameter_name, const std::string &vuid,
+                             const LogMiscParams &misc) {
+        bool skip_call = false;
+
+        if (value <= lower_bound) {
+            std::ostringstream ss;
+            ss << misc.api_name << ": parameter " << parameter_name.get_name() << " (= " << value << ") is greater than "
+               << lower_bound;
+            skip_call |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, misc.objectType, misc.srcObject, vuid, "%s", ss.str().c_str());
+        }
+
+        return skip_call;
+    }
+
+    template <typename T>
+    bool ValidateGreaterThanZero(const T value, const ParameterName &parameter_name, const std::string &vuid,
+                                 const LogMiscParams &misc) {
+        return ValidateGreaterThan(value, T{0}, parameter_name, vuid, misc);
+    }
+    /**
+     * Validate a required pointer.
+     *
+     * Verify that a required pointer is not NULL.
+     *
+     * @param apiName Name of API call being validated.
+     * @param parameterName Name of parameter being validated.
+     * @param value Pointer to validate.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_required_pointer(const char *apiName, const ParameterName &parameterName, const void *value,
+                                   const std::string &vuid) {
+        bool skip_call = false;
+
+        if (value == NULL) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                 "%s: required parameter %s specified as NULL.", apiName, parameterName.get_name().c_str());
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate array count and pointer to array.
+     *
+     * Verify that required count and array parameters are not 0 or NULL.  If the
+     * count parameter is not optional, verify that it is not 0.  If the array
+     * parameter is NULL, and it is not optional, verify that count is 0.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param count Number of elements in the array.
+     * @param array Array to validate.
+     * @param countRequired The 'count' parameter may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T1, typename T2>
+    bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, T1 count,
+                        const T2 *array, bool countRequired, bool arrayRequired, const char *count_required_vuid,
+                        const char *array_required_vuid) {
+        bool skip_call = false;
+
+        // Count parameters not tagged as optional cannot be 0
+        if (countRequired && (count == 0)) {
+            skip_call |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, count_required_vuid,
+                        "%s: parameter %s must be greater than 0.", apiName, countName.get_name().c_str());
+        }
+
+        // Array parameters not tagged as optional cannot be NULL, unless the count is 0
+        if (arrayRequired && (count != 0) && (*array == NULL)) {
+            skip_call |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, array_required_vuid,
+                        "%s: required parameter %s specified as NULL.", apiName, arrayName.get_name().c_str());
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate pointer to array count and pointer to array.
+     *
+     * Verify that required count and array parameters are not NULL.  If count
+     * is not NULL and its value is not optional, verify that it is not 0.  If the
+     * array parameter is NULL, and it is not optional, verify that count is 0.
+     * The array parameter will typically be optional for this case (where count is
+     * a pointer), allowing the caller to retrieve the available count.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param count Pointer to the number of elements in the array.
+     * @param array Array to validate.
+     * @param countPtrRequired The 'count' parameter may not be NULL when true.
+     * @param countValueRequired The '*count' value may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T1, typename T2>
+    bool validate_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, const T1 *count,
+                        const T2 *array, bool countPtrRequired, bool countValueRequired, bool arrayRequired,
+                        const char *count_required_vuid, const char *array_required_vuid) {
+        bool skip_call = false;
+
+        if (count == NULL) {
+            if (countPtrRequired) {
+                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                     kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
+                                     countName.get_name().c_str());
+            }
+        } else {
+            skip_call |= validate_array(apiName, countName, arrayName, *array ? (*count) : 0, &array, countValueRequired,
+                                        arrayRequired, count_required_vuid, array_required_vuid);
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate a pointer to a Vulkan structure.
+     *
+     * Verify that a required pointer to a structure is not NULL.  If the pointer is
+     * not NULL, verify that each structure's sType field is set to the correct
+     * VkStructureType value.
+     *
+     * @param apiName Name of API call being validated.
+     * @param parameterName Name of struct parameter being validated.
+     * @param sTypeName Name of expected VkStructureType value.
+     * @param value Pointer to the struct to validate.
+     * @param sType VkStructureType for structure validation.
+     * @param required The parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_struct_type(const char *apiName, const ParameterName &parameterName, const char *sTypeName, const T *value,
+                              VkStructureType sType, bool required, const char *struct_vuid, const char *stype_vuid) {
+        bool skip_call = false;
+
+        if (value == NULL) {
+            if (required) {
+                skip_call |=
+                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, struct_vuid,
+                            "%s: required parameter %s specified as NULL", apiName, parameterName.get_name().c_str());
+            }
+        } else if (value->sType != sType) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
+                                 "%s: parameter %s->sType must be %s.", apiName, parameterName.get_name().c_str(), sTypeName);
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate an array of Vulkan structures
+     *
+     * Verify that required count and array parameters are not 0 or NULL.  If
+     * the array contains 1 or more structures, verify that each structure's
+     * sType field is set to the correct VkStructureType value.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param sTypeName Name of expected VkStructureType value.
+     * @param count Number of elements in the array.
+     * @param array Array to validate.
+     * @param sType VkStructureType for structure validation.
+     * @param countRequired The 'count' parameter may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
+                                    const char *sTypeName, uint32_t count, const T *array, VkStructureType sType,
+                                    bool countRequired, bool arrayRequired, const char *stype_vuid, const char *param_vuid,
+                                    const char *count_required_vuid) {
+        bool skip_call = false;
+
+        if ((count == 0) || (array == NULL)) {
+            skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
+                                        count_required_vuid, param_vuid);
+        } else {
+            // Verify that all structs in the array have the correct type
+            for (uint32_t i = 0; i < count; ++i) {
+                if (array[i].sType != sType) {
+                    skip_call |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, stype_vuid,
+                                "%s: parameter %s[%d].sType must be %s", apiName, arrayName.get_name().c_str(), i, sTypeName);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate an array of Vulkan structures.
+     *
+     * Verify that required count and array parameters are not NULL.  If count
+     * is not NULL and its value is not optional, verify that it is not 0.
+     * If the array contains 1 or more structures, verify that each structure's
+     * sType field is set to the correct VkStructureType value.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param sTypeName Name of expected VkStructureType value.
+     * @param count Pointer to the number of elements in the array.
+     * @param array Array to validate.
+     * @param sType VkStructureType for structure validation.
+     * @param countPtrRequired The 'count' parameter may not be NULL when true.
+     * @param countValueRequired The '*count' value may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_struct_type_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
+                                    const char *sTypeName, uint32_t *count, const T *array, VkStructureType sType,
+                                    bool countPtrRequired, bool countValueRequired, bool arrayRequired, const char *stype_vuid,
+                                    const char *param_vuid, const char *count_required_vuid) {
+        bool skip_call = false;
+
+        if (count == NULL) {
+            if (countPtrRequired) {
+                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                     kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as NULL", apiName,
+                                     countName.get_name().c_str());
+            }
+        } else {
+            skip_call |= validate_struct_type_array(apiName, countName, arrayName, sTypeName, (*count), array, sType,
+                                                    countValueRequired, arrayRequired, stype_vuid, param_vuid, count_required_vuid);
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate a Vulkan handle.
+     *
+     * Verify that the specified handle is not VK_NULL_HANDLE.
+     *
+     * @param api_name Name of API call being validated.
+     * @param parameter_name Name of struct parameter being validated.
+     * @param value Handle to validate.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_required_handle(const char *api_name, const ParameterName &parameter_name, T value) {
+        bool skip_call = false;
+
+        if (value == VK_NULL_HANDLE) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                 kVUID_PVError_RequiredParameter, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name,
+                                 parameter_name.get_name().c_str());
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate an array of Vulkan handles.
+     *
+     * Verify that required count and array parameters are not NULL.  If count
+     * is not NULL and its value is not optional, verify that it is not 0.
+     * If the array contains 1 or more handles, verify that no handle is set to
+     * VK_NULL_HANDLE.
+     *
+     * @note This function is only intended to validate arrays of handles when none
+     *       of the handles are allowed to be VK_NULL_HANDLE.  For arrays of handles
+     *       that are allowed to contain VK_NULL_HANDLE, use validate_array() instead.
+     *
+     * @param api_name Name of API call being validated.
+     * @param count_name Name of count parameter.
+     * @param array_name Name of array parameter.
+     * @param count Number of elements in the array.
+     * @param array Array to validate.
+     * @param count_required The 'count' parameter may not be 0 when true.
+     * @param array_required The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_handle_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name,
+                               uint32_t count, const T *array, bool count_required, bool array_required) {
+        bool skip_call = false;
+
+        if ((count == 0) || (array == NULL)) {
+            skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required,
+                                        kVUIDUndefined, kVUIDUndefined);
+        } else {
+            // Verify that no handles in the array are VK_NULL_HANDLE
+            for (uint32_t i = 0; i < count; ++i) {
+                if (array[i] == VK_NULL_HANDLE) {
+                    skip_call |=
+                        log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE",
+                                api_name, array_name.get_name().c_str(), i);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate string array count and content.
+     *
+     * Verify that required count and array parameters are not 0 or NULL.  If the
+     * count parameter is not optional, verify that it is not 0.  If the array
+     * parameter is NULL, and it is not optional, verify that count is 0.  If the
+     * array parameter is not NULL, verify that none of the strings are NULL.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param count Number of strings in the array.
+     * @param array Array of strings to validate.
+     * @param countRequired The 'count' parameter may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_string_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName, uint32_t count,
+                               const char *const *array, bool countRequired, bool arrayRequired, const char *count_required_vuid,
+                               const char *array_required_vuid) {
+        bool skip_call = false;
+
+        if ((count == 0) || (array == NULL)) {
+            skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
+                                        count_required_vuid, array_required_vuid);
+        } else {
+            // Verify that strings in the array are not NULL
+            for (uint32_t i = 0; i < count; ++i) {
+                if (array[i] == NULL) {
+                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                         kVUID_PVError_RequiredParameter, "%s: required parameter %s[%d] specified as NULL",
+                                         apiName, arrayName.get_name().c_str(), i);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    // Forward declaration for pNext validation
+    bool ValidatePnextStructContents(const char *api_name, const ParameterName &parameter_name, const GenericHeader *header);
+
+    /**
+     * Validate a structure's pNext member.
+     *
+     * Verify that the specified pNext value points to the head of a list of
+     * allowed extension structures.  If no extension structures are allowed,
+     * verify that pNext is null.
+     *
+     * @param api_name Name of API call being validated.
+     * @param parameter_name Name of parameter being validated.
+     * @param allowed_struct_names Names of allowed structs.
+     * @param next Pointer to validate.
+     * @param allowed_type_count Total number of allowed structure types.
+     * @param allowed_types Array of structure types allowed for pNext.
+     * @param header_version Version of header defining the pNext validation rules.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_struct_pnext(const char *api_name, const ParameterName &parameter_name, const char *allowed_struct_names,
+                               const void *next, size_t allowed_type_count, const VkStructureType *allowed_types,
+                               uint32_t header_version, const char *vuid) {
+        bool skip_call = false;
+
+        // TODO: The valid pNext structure types are not recursive. Each structure has its own list of valid sTypes for pNext.
+        // Codegen a map of vectors containing the allowable pNext types for each struct and use that here -- also simplifies parms.
+        if (next != NULL) {
+            std::unordered_set<const void *> cycle_check;
+            std::unordered_set<VkStructureType, std::hash<int>> unique_stype_check;
+
+            const char *disclaimer =
+                "This warning is based on the Valid Usage documentation for version %d of the Vulkan header.  It is possible that "
+                "you "
+                "are "
+                "using a struct from a private extension or an extension that was added to a later version of the Vulkan header, "
+                "in "
+                "which "
+                "case your use of %s is perfectly valid but is not guaranteed to work correctly with validation enabled";
+
+            if (allowed_type_count == 0) {
+                std::string message = "%s: value of %s must be NULL. ";
+                message += disclaimer;
+                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                     message.c_str(), api_name, parameter_name.get_name().c_str(), header_version,
+                                     parameter_name.get_name().c_str());
+            } else {
+                const VkStructureType *start = allowed_types;
+                const VkStructureType *end = allowed_types + allowed_type_count;
+                const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
+
+                cycle_check.insert(next);
+
+                while (current != NULL) {
+                    if (((strncmp(api_name, "vkCreateInstance", strlen(api_name)) != 0) ||
+                         (current->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)) &&
+                        ((strncmp(api_name, "vkCreateDevice", strlen(api_name)) != 0) ||
+                         (current->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO))) {
+                        if (cycle_check.find(current->pNext) != cycle_check.end()) {
+                            std::string message = "%s: %s chain contains a cycle -- pNext pointer " PRIx64 " is repeated.";
+                            skip_call |=
+                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                        kVUID_PVError_InvalidStructPNext, message.c_str(), api_name,
+                                        parameter_name.get_name().c_str(), reinterpret_cast<uint64_t>(next));
+                            break;
+                        } else {
+                            cycle_check.insert(current->pNext);
+                        }
+
+                        std::string type_name = string_VkStructureType(current->sType);
+                        if (unique_stype_check.find(current->sType) != unique_stype_check.end()) {
+                            std::string message = "%s: %s chain contains duplicate structure types: %s appears multiple times.";
+                            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                                 VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_PVError_InvalidStructPNext,
+                                                 message.c_str(), api_name, parameter_name.get_name().c_str(), type_name.c_str());
+                        } else {
+                            unique_stype_check.insert(current->sType);
+                        }
+
+                        if (std::find(start, end, current->sType) == end) {
+                            if (type_name == UnsupportedStructureTypeString) {
+                                std::string message =
+                                    "%s: %s chain includes a structure with unknown VkStructureType (%d); Allowed structures are "
+                                    "[%s]. ";
+                                message += disclaimer;
+                                skip_call |=
+                                    log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
+                                            0, vuid, message.c_str(), api_name, parameter_name.get_name().c_str(), current->sType,
+                                            allowed_struct_names, header_version, parameter_name.get_name().c_str());
+                            } else {
+                                std::string message =
+                                    "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are "
+                                    "[%s]. ";
+                                message += disclaimer;
+                                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
+                                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid, message.c_str(), api_name,
+                                                     parameter_name.get_name().c_str(), type_name.c_str(), allowed_struct_names,
+                                                     header_version, parameter_name.get_name().c_str());
+                            }
+                        }
+                        skip_call |= ValidatePnextStructContents(api_name, parameter_name, current);
+                    }
+                    current = reinterpret_cast<const GenericHeader *>(current->pNext);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate a VkBool32 value.
+     *
+     * Generate a warning if a VkBool32 value is neither VK_TRUE nor VK_FALSE.
+     *
+     * @param apiName Name of API call being validated.
+     * @param parameterName Name of parameter being validated.
+     * @param value Boolean value to validate.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_bool32(const char *apiName, const ParameterName &parameterName, VkBool32 value) {
+        bool skip_call = false;
+
+        if ((value != VK_TRUE) && (value != VK_FALSE)) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                 kVUID_PVError_UnrecognizedValue, "%s: value of %s (%d) is neither VK_TRUE nor VK_FALSE", apiName,
+                                 parameterName.get_name().c_str(), value);
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate a Vulkan enumeration value.
+     *
+     * Generate a warning if an enumeration token value does not fall within the core enumeration
+     * begin and end token values, and was not added to the enumeration by an extension.  Extension
+     * provided enumerations use the equation specified in Appendix C.10 of the Vulkan specification,
+     * with 1,000,000,000 as the base token value.
+     *
+     * @note This function does not expect to process enumerations defining bitmask flag bits.
+     *
+     * @param apiName Name of API call being validated.
+     * @param parameterName Name of parameter being validated.
+     * @param enumName Name of the enumeration being validated.
+     * @param valid_values The list of valid values for the enumeration.
+     * @param value Enumeration value to validate.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_ranged_enum(const char *apiName, const ParameterName &parameterName, const char *enumName,
+                              const std::vector<T> &valid_values, T value, const char *vuid) {
+        bool skip = false;
+
+        if (std::find(valid_values.begin(), valid_values.end(), value) == valid_values.end()) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                        "%s: value of %s (%d) does not fall within the begin..end range of the core %s enumeration tokens and is "
+                        "not an extension added token.",
+                        apiName, parameterName.get_name().c_str(), value, enumName);
+        }
+
+        return skip;
+    }
+
+    /**
+     * Validate an array of Vulkan enumeration value.
+     *
+     * Process all enumeration token values in the specified array and generate a warning if a value
+     * does not fall within the core enumeration begin and end token values, and was not added to
+     * the enumeration by an extension.  Extension provided enumerations use the equation specified
+     * in Appendix C.10 of the Vulkan specification, with 1,000,000,000 as the base token value.
+     *
+     * @note This function does not expect to process enumerations defining bitmask flag bits.
+     *
+     * @param apiName Name of API call being validated.
+     * @param countName Name of count parameter.
+     * @param arrayName Name of array parameter.
+     * @param enumName Name of the enumeration being validated.
+     * @param valid_values The list of valid values for the enumeration.
+     * @param count Number of enumeration values in the array.
+     * @param array Array of enumeration values to validate.
+     * @param countRequired The 'count' parameter may not be 0 when true.
+     * @param arrayRequired The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    template <typename T>
+    bool validate_ranged_enum_array(const char *apiName, const ParameterName &countName, const ParameterName &arrayName,
+                                    const char *enumName, const std::vector<T> &valid_values, uint32_t count, const T *array,
+                                    bool countRequired, bool arrayRequired) {
+        bool skip_call = false;
+
+        if ((count == 0) || (array == NULL)) {
+            skip_call |= validate_array(apiName, countName, arrayName, count, &array, countRequired, arrayRequired, kVUIDUndefined,
+                                        kVUIDUndefined);
+        } else {
+            for (uint32_t i = 0; i < count; ++i) {
+                if (std::find(valid_values.begin(), valid_values.end(), array[i]) == valid_values.end()) {
+                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                         kVUID_PVError_UnrecognizedValue,
+                                         "%s: value of %s[%d] (%d) does not fall within the begin..end range of the core %s "
+                                         "enumeration tokens and is not an extension added token",
+                                         apiName, arrayName.get_name().c_str(), i, array[i], enumName);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Verify that a reserved VkFlags value is zero.
+     *
+     * Verify that the specified value is zero, to check VkFlags values that are reserved for
+     * future use.
+     *
+     * @param api_name Name of API call being validated.
+     * @param parameter_name Name of parameter being validated.
+     * @param value Value to validate.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_reserved_flags(const char *api_name, const ParameterName &parameter_name, VkFlags value, const char *vuid) {
+        bool skip_call = false;
+
+        if (value != 0) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                 "%s: parameter %s must be 0.", api_name, parameter_name.get_name().c_str());
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate a Vulkan bitmask value.
+     *
+     * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
+     * for that type.
+     *
+     * @param api_name Name of API call being validated.
+     * @param parameter_name Name of parameter being validated.
+     * @param flag_bits_name Name of the VkFlags type being validated.
+     * @param all_flags A bit mask combining all valid flag bits for the VkFlags type being validated.
+     * @param value VkFlags value to validate.
+     * @param flags_required The 'value' parameter may not be 0 when true.
+     * @param singleFlag The 'value' parameter may not contain more than one bit from all_flags.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_flags(const char *api_name, const ParameterName &parameter_name, const char *flag_bits_name, VkFlags all_flags,
+                        VkFlags value, bool flags_required, bool singleFlag, const char *vuid) {
+        bool skip_call = false;
+
+        if (value == 0) {
+            if (flags_required) {
+                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                     "%s: value of %s must not be 0.", api_name, parameter_name.get_name().c_str());
+            }
+        } else if ((value & (~all_flags)) != 0) {
+            skip_call |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                        kVUID_PVError_UnrecognizedValue, "%s: value of %s contains flag bits that are not recognized members of %s",
+                        api_name, parameter_name.get_name().c_str(), flag_bits_name);
+        } else if (singleFlag && (std::bitset<sizeof(VkFlags) * 8>(value).count() > 1)) {
+            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                 kVUID_PVError_UnrecognizedValue,
+                                 "%s: value of %s contains multiple members of %s when only a single value is allowed", api_name,
+                                 parameter_name.get_name().c_str(), flag_bits_name);
+        }
+
+        return skip_call;
+    }
+
+    /**
+     * Validate an array of Vulkan bitmask values.
+     *
+     * Generate a warning if a value with a VkFlags derived type does not contain valid flag bits
+     * for that type.
+     *
+     * @param api_name Name of API call being validated.
+     * @param count_name Name of parameter being validated.
+     * @param array_name Name of parameter being validated.
+     * @param flag_bits_name Name of the VkFlags type being validated.
+     * @param all_flags A bitmask combining all valid flag bits for the VkFlags type being validated.
+     * @param count Number of VkFlags values in the array.
+     * @param array Array of VkFlags value to validate.
+     * @param count_required The 'count' parameter may not be 0 when true.
+     * @param array_required The 'array' parameter may not be NULL when true.
+     * @return Boolean value indicating that the call should be skipped.
+     */
+    bool validate_flags_array(const char *api_name, const ParameterName &count_name, const ParameterName &array_name,
+                              const char *flag_bits_name, VkFlags all_flags, uint32_t count, const VkFlags *array,
+                              bool count_required, bool array_required) {
+        bool skip_call = false;
+
+        if ((count == 0) || (array == NULL)) {
+            skip_call |= validate_array(api_name, count_name, array_name, count, &array, count_required, array_required,
+                                        kVUIDUndefined, kVUIDUndefined);
+        } else {
+            // Verify that all VkFlags values in the array
+            for (uint32_t i = 0; i < count; ++i) {
+                if (array[i] == 0) {
+                    // Current XML registry logic for validity generation uses the array parameter's optional tag to determine if
+                    // elements in the array are allowed be 0
+                    if (array_required) {
+                        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                             kVUID_PVError_RequiredParameter, "%s: value of %s[%d] must not be 0", api_name,
+                                             array_name.get_name().c_str(), i);
+                    }
+                } else if ((array[i] & (~all_flags)) != 0) {
+                    skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                         kVUID_PVError_UnrecognizedValue,
+                                         "%s: value of %s[%d] contains flag bits that are not recognized members of %s", api_name,
+                                         array_name.get_name().c_str(), i, flag_bits_name);
+                }
+            }
+        }
+
+        return skip_call;
+    }
+
+    template <typename ExtensionState>
+    bool validate_extension_reqs(const ExtensionState &extensions, const char *vuid, const char *extension_type,
+                                 const char *extension_name) {
+        bool skip = false;
+        if (!extension_name) {
+            return skip;  // Robust to invalid char *
+        }
+        auto info = ExtensionState::get_info(extension_name);
+
+        if (!info.state) {
+            return skip;  // Unknown extensions cannot be checked so report OK
+        }
+
+        // Check against the required list in the info
+        std::vector<const char *> missing;
+        for (const auto &req : info.requires) {
+            if (!(extensions.*(req.enabled))) {
+                missing.push_back(req.name);
+            }
+        }
+
+        // Report any missing requirements
+        if (missing.size()) {
+            std::string missing_joined_list = string_join(", ", missing);
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+                            HandleToUint64(instance), vuid, "Missing extension%s required by the %s extension %s: %s.",
+                            ((missing.size() > 1) ? "s" : ""), extension_type, extension_name, missing_joined_list.c_str());
+        }
+        return skip;
+    }
+
+    enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
+
+    template <typename RenderPassCreateInfoGeneric>
+    bool CreateRenderPassGeneric(VkDevice device, const RenderPassCreateInfoGeneric *pCreateInfo,
+                                 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
+                                 RenderPassCreateVersion rp_version) {
+        bool skip = false;
+        uint32_t max_color_attachments = device_limits.maxColorAttachments;
+        bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
+        const char *vuid;
+
+        for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
+            if (pCreateInfo->pAttachments[i].format == VK_FORMAT_UNDEFINED) {
+                std::stringstream ss;
+                ss << (use_rp2 ? "vkCreateRenderPass2KHR" : "vkCreateRenderPass") << ": pCreateInfo->pAttachments[" << i
+                   << "].format is VK_FORMAT_UNDEFINED. ";
+                vuid =
+                    use_rp2 ? "VUID-VkAttachmentDescription2KHR-format-parameter" : "VUID-VkAttachmentDescription-format-parameter";
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                "%s", ss.str().c_str());
+            }
+            if (pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
+                pCreateInfo->pAttachments[i].finalLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
+                vuid = use_rp2 ? "VUID-VkAttachmentDescription2KHR-finalLayout-03061"
+                               : "VUID-VkAttachmentDescription-finalLayout-00843";
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                "pCreateInfo->pAttachments[%d].finalLayout must not be VK_IMAGE_LAYOUT_UNDEFINED or "
+                                "VK_IMAGE_LAYOUT_PREINITIALIZED.",
+                                i);
+            }
+        }
+
+        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
+            if (pCreateInfo->pSubpasses[i].colorAttachmentCount > max_color_attachments) {
+                vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063"
+                               : "VUID-VkSubpassDescription-colorAttachmentCount-00845";
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
+                                "Cannot create a render pass with %d color attachments. Max is %d.",
+                                pCreateInfo->pSubpasses[i].colorAttachmentCount, max_color_attachments);
+            }
+        }
+        return skip;
+    }
+
+    template <typename T>
+    void RecordRenderPass(VkRenderPass renderPass, const T *pCreateInfo) {
+        std::unique_lock<std::mutex> lock(renderpass_map_mutex);
+        auto &renderpass_state = renderpasses_states[renderPass];
+        lock.unlock();
+
+        for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
+            bool uses_color = false;
+            for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
+                if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
+
+            bool uses_depthstencil = false;
+            if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
+                if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
+                    uses_depthstencil = true;
+
+            if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
+            if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
+        }
+    }
+
+    bool require_device_extension(bool flag, char const *function_name, char const *extension_name);
+
+    bool validate_instance_extensions(const VkInstanceCreateInfo *pCreateInfo);
+
+    bool validate_api_version(uint32_t api_version, uint32_t effective_api_version);
+
+    bool validate_string(const char *apiName, const ParameterName &stringName, const std::string &vuid, const char *validateString);
+
+    bool ValidateCoarseSampleOrderCustomNV(const VkCoarseSampleOrderCustomNV *order);
+
+    bool ValidateQueueFamilies(uint32_t queue_family_count, const uint32_t *queue_families, const char *cmd_name,
+                               const char *array_parameter_name, const std::string &unique_error_code,
+                               const std::string &valid_error_code, bool optional);
+
+    bool ValidateDeviceQueueFamily(uint32_t queue_family, const char *cmd_name, const char *parameter_name,
+                                   const std::string &error_code, bool optional);
+
+    bool OutputExtensionError(const std::string &api_name, const std::string &extension_name);
+
+    void PostCallRecordCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                        const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result);
+    void PostCallRecordCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass, VkResult result);
+    void PostCallRecordDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator);
+    void PostCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
+                                    const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result);
+
+    void PostCallRecordCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
+                                      VkInstance *pInstance, VkResult result);
+
+    bool manual_PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool);
+
+    bool manual_PreCallValidateCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
+                                              VkInstance *pInstance);
+
+    bool manual_PreCallValidateCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice);
+
+    bool manual_PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer);
+
+    bool manual_PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
+                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage);
+
+    bool manual_PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
+                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView);
+
+    bool manual_PreCallValidateViewport(const VkViewport &viewport, const char *fn_name, const ParameterName &parameter_name,
+                                        VkDebugReportObjectTypeEXT object_type, uint64_t object);
+
+    bool manual_PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
+                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);
+    bool manual_PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
+                                                      const VkComputePipelineCreateInfo *pCreateInfos,
+                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines);
+
+    bool manual_PreCallValidateCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
+                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler);
+    bool manual_PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+                                                         const VkAllocationCallbacks *pAllocator,
+                                                         VkDescriptorSetLayout *pSetLayout);
+
+    bool manual_PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
+                                                    const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
+                                                    const VkCopyDescriptorSet *pDescriptorCopies);
+    ;
+    bool manual_PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount,
+                                                  const VkDescriptorSet *pDescriptorSets);
+
+    bool manual_PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+
+    bool manual_PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+
+    bool manual_PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                  const VkCommandBuffer *pCommandBuffers);
+
+    bool manual_PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo);
+
+    bool manual_PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
+                                              const VkViewport *pViewports);
+
+    bool manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
+                                             const VkRect2D *pScissors);
+    bool manual_PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth);
+
+    bool manual_PreCallValidateCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
+                                       uint32_t firstVertex, uint32_t firstInstance);
+
+    bool manual_PreCallValidateCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
+                                               uint32_t stride);
+
+    bool manual_PreCallValidateCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                      uint32_t count, uint32_t stride);
+
+    bool manual_PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                            const VkImageCopy *pRegions);
+
+    bool manual_PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
+                                            const VkImageBlit *pRegions, VkFilter filter);
+
+    bool manual_PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
+                                                    VkImageLayout dstImageLayout, uint32_t regionCount,
+                                                    const VkBufferImageCopy *pRegions);
+
+    bool manual_PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
+                                                    VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions);
+
+    bool manual_PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                               VkDeviceSize dataSize, const void *pData);
+
+    bool manual_PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
+                                             VkDeviceSize size, uint32_t data);
+
+    bool manual_PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain);
+    bool manual_PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo);
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+    bool manual_PreCallValidateCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
+                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface);
+#endif  // VK_USE_PLATFORM_WIN32_KHR
+
+    bool manual_PreCallValidateCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool);
+    bool manual_PreCallValidateCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY,
+                                           uint32_t groupCountZ);
+
+    bool manual_PreCallValidateCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
+
+    bool manual_PreCallValidateCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY,
+                                                  uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY,
+                                                  uint32_t groupCountZ);
+    bool manual_PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
+                                                        uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors);
+    bool manual_PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
+                                                                  uint32_t viewportCount,
+                                                                  const VkShadingRatePaletteNV *pShadingRatePalettes);
+
+    bool manual_PreCallValidateCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType,
+                                                         uint32_t customSampleOrderCount,
+                                                         const VkCoarseSampleOrderCustomNV *pCustomSampleOrders);
+
+    bool manual_PreCallValidateCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask);
+    bool manual_PreCallValidateCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                          uint32_t drawCount, uint32_t stride);
+
+    bool manual_PreCallValidateCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
+                                                               VkBuffer countBuffer, VkDeviceSize countBufferOffset,
+                                                               uint32_t maxDrawCount, uint32_t stride);
+
+    bool manual_PreCallValidateEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
+                                                                  uint32_t *pPropertyCount, VkExtensionProperties *pProperties);
+    bool manual_PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
+                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory);
+#include "parameter_validation.h"
+};  // Class StatelessValidation
diff --git a/layers/threading.cpp b/layers/threading.cpp
deleted file mode 100644
index 08020ad..0000000
--- a/layers/threading.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (C) 2015-2018 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unordered_map>
-#include <list>
-
-#include "vk_loader_platform.h"
-#include "vulkan/vk_layer.h"
-#include "vk_layer_config.h"
-#include "vk_layer_extension_utils.h"
-#include "vk_layer_utils.h"
-#include "vk_layer_logging.h"
-#include "threading.h"
-#include "vk_dispatch_table_helper.h"
-#include "vk_enum_string_helper.h"
-#include "vk_layer_data.h"
-#include "vk_layer_utils.h"
-
-#include "thread_check.h"
-
-namespace threading {
-
-static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-
-static void initThreading(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_report_actions(my_data->report_data, my_data->logging_callback, pAllocator, "google_threading");
-    layer_debug_messenger_actions(my_data->report_data, my_data->logging_messenger, pAllocator, "google_threading");
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                                              VkInstance *pInstance) {
-    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
-    if (fpCreateInstance == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
-    if (result != VK_SUCCESS) return result;
-
-    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
-    my_data->instance = *pInstance;
-    my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
-    layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
-
-    my_data->report_data = debug_utils_create_instance(my_data->instance_dispatch_table, *pInstance,
-                                                       pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
-    initThreading(my_data, pAllocator);
-
-    // Look for one or more debug report create info structures, and copy the
-    // callback(s) for each one found (for use by vkDestroyInstance)
-    layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &my_data->num_tmp_debug_messengers, &my_data->tmp_messenger_create_infos,
-                                    &my_data->tmp_debug_messengers);
-    layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &my_data->num_tmp_report_callbacks, &my_data->tmp_report_create_infos,
-                                    &my_data->tmp_report_callbacks);
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(instance);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
-
-    // Enable the temporary callback(s) here to catch cleanup issues:
-    bool callback_setup = false;
-    if (my_data->num_tmp_debug_messengers > 0) {
-        if (!layer_enable_tmp_debug_messengers(my_data->report_data, my_data->num_tmp_debug_messengers,
-                                               my_data->tmp_messenger_create_infos, my_data->tmp_debug_messengers)) {
-            callback_setup = true;
-        }
-    }
-    if (my_data->num_tmp_report_callbacks > 0) {
-        if (!layer_enable_tmp_report_callbacks(my_data->report_data, my_data->num_tmp_report_callbacks,
-                                               my_data->tmp_report_create_infos, my_data->tmp_report_callbacks)) {
-            callback_setup = true;
-        }
-    }
-
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startWriteObject(my_data, instance);
-    }
-    pTable->DestroyInstance(instance, pAllocator);
-    if (threadChecks) {
-        finishWriteObject(my_data, instance);
-    } else {
-        finishMultiThread();
-    }
-
-    // Disable and cleanup the temporary callback(s):
-    if (callback_setup) {
-        layer_disable_tmp_debug_messengers(my_data->report_data, my_data->num_tmp_debug_messengers, my_data->tmp_debug_messengers);
-        layer_disable_tmp_report_callbacks(my_data->report_data, my_data->num_tmp_report_callbacks, my_data->tmp_report_callbacks);
-    }
-    if (my_data->num_tmp_debug_messengers > 0) {
-        layer_free_tmp_debug_messengers(my_data->tmp_messenger_create_infos, my_data->tmp_debug_messengers);
-        my_data->num_tmp_debug_messengers = 0;
-    }
-    if (my_data->num_tmp_report_callbacks > 0) {
-        layer_free_tmp_report_callbacks(my_data->tmp_report_create_infos, my_data->tmp_report_callbacks);
-        my_data->num_tmp_report_callbacks = 0;
-    }
-
-    // Clean up logging callbacks, if any
-    while (my_data->logging_messenger.size() > 0) {
-        VkDebugUtilsMessengerEXT messenger = my_data->logging_messenger.back();
-        layer_destroy_messenger_callback(my_data->report_data, messenger, pAllocator);
-        my_data->logging_messenger.pop_back();
-    }
-    while (my_data->logging_callback.size() > 0) {
-        VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
-        layer_destroy_report_callback(my_data->report_data, callback, pAllocator);
-        my_data->logging_callback.pop_back();
-    }
-
-    layer_debug_utils_destroy_instance(my_data->report_data);
-    delete my_data->instance_dispatch_table;
-    FreeLayerDataPtr(key, layer_data_map);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
-                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
-    layer_data *my_instance_data = GetLayerDataPtr(get_dispatch_key(gpu), layer_data_map);
-    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
-    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
-    if (fpCreateDevice == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-
-    // Setup device dispatch table
-    my_device_data->device_dispatch_table = new VkLayerDispatchTable;
-    layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
-    // Save pCreateInfo device extension list for GetDeviceProcAddr()
-    for (uint32_t extn = 0; extn < pCreateInfo->enabledExtensionCount; extn++) {
-        my_device_data->device_extension_set.insert(pCreateInfo->ppEnabledExtensionNames[extn]);
-    }
-
-    my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startWriteObject(dev_data, device);
-    }
-    dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
-    if (threadChecks) {
-        finishWriteObject(dev_data, device);
-    } else {
-        finishMultiThread();
-    }
-
-    delete dev_data->device_dispatch_table;
-    FreeLayerDataPtr(key, layer_data_map);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
-                                                     VkImage *pSwapchainImages) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
-    VkResult result;
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, device);
-        startReadObject(my_data, swapchain);
-    }
-    result = pTable->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
-    if (threadChecks) {
-        finishReadObject(my_data, device);
-        finishReadObject(my_data, swapchain);
-    } else {
-        finishMultiThread();
-    }
-    return result;
-}
-
-static const VkExtensionProperties threading_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
-                                                             {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
-
-static const VkLayerProperties layerProps = {
-    "VK_LAYER_GOOGLE_threading",
-    VK_LAYER_API_VERSION,  // specVersion
-    1,
-    "Google Validation Layer",
-};
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &layerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                              VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &layerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                    VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, layerProps.layerName))
-        return util_GetExtensionProperties(1, threading_extensions, pCount, pProperties);
-
-    return VK_ERROR_LAYER_NOT_PRESENT;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
-                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
-    // Threading layer does not have any device extensions
-    if (pLayerName && !strcmp(pLayerName, layerProps.layerName))
-        return util_GetExtensionProperties(0, nullptr, pCount, pProperties);
-
-    assert(physicalDevice);
-
-    dispatch_key key = get_dispatch_key(physicalDevice);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
-}
-
-// Need to prototype this call because it's internal and does not show up in vk.xml
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (!ApiParentExtensionEnabled(funcName, device_data->device_extension_set)) {
-        return nullptr;
-    }
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-    auto &table = device_data->device_dispatch_table;
-    if (!table->GetDeviceProcAddr) return nullptr;
-    return table->GetDeviceProcAddr(device, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-
-    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    auto &table = instance_data->instance_dispatch_table;
-    if (!table->GetInstanceProcAddr) return nullptr;
-    return table->GetInstanceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
-    assert(instance);
-
-    layer_data *my_data;
-    my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
-
-    if (pTable->GetPhysicalDeviceProcAddr == NULL) return NULL;
-    return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-// VK_EXT_debug_utils commands
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugUtilsMessengerEXT *pMessenger) {
-    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, instance);
-    }
-    VkResult result = my_data->instance_dispatch_table->CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-
-    if (VK_SUCCESS == result) {
-        result = layer_create_messenger_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
-        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
-        if (VK_SUCCESS != result) {
-            my_data->instance_dispatch_table->DestroyDebugUtilsMessengerEXT(instance, *pMessenger, pAllocator);
-        }
-    }
-    if (threadChecks) {
-        finishReadObject(my_data, instance);
-    } else {
-        finishMultiThread();
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, instance);
-        startWriteObject(my_data, messenger);
-    }
-    my_data->instance_dispatch_table->DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-    layer_destroy_messenger_callback(my_data->report_data, messenger, pAllocator);
-    if (threadChecks) {
-        finishReadObject(my_data, instance);
-        finishWriteObject(my_data, messenger);
-    } else {
-        finishMultiThread();
-    }
-}
-
-// VK_EXT_debug_report commands
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
-                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugReportCallbackEXT *pMsgCallback) {
-    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, instance);
-    }
-    VkResult result =
-        my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-    if (VK_SUCCESS == result) {
-        result = layer_create_report_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
-        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
-        if (VK_SUCCESS != result) {
-            my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, *pMsgCallback, pAllocator);
-        }
-    }
-    if (threadChecks) {
-        finishReadObject(my_data, instance);
-    } else {
-        finishMultiThread();
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, instance);
-        startWriteObject(my_data, callback);
-    }
-    my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
-    layer_destroy_report_callback(my_data->report_data, callback, pAllocator);
-    if (threadChecks) {
-        finishReadObject(my_data, instance);
-        finishWriteObject(my_data, callback);
-    } else {
-        finishMultiThread();
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
-                                                      VkCommandBuffer *pCommandBuffers) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
-    VkResult result;
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, device);
-        startWriteObject(my_data, pAllocateInfo->commandPool);
-    }
-
-    result = pTable->AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
-    if (threadChecks) {
-        finishReadObject(my_data, device);
-        finishWriteObject(my_data, pAllocateInfo->commandPool);
-    } else {
-        finishMultiThread();
-    }
-
-    // Record mapping from command buffer to command pool
-    if (VK_SUCCESS == result) {
-        for (uint32_t index = 0; index < pAllocateInfo->commandBufferCount; index++) {
-            std::lock_guard<std::mutex> lock(command_pool_lock);
-            command_pool_map[pCommandBuffers[index]] = pAllocateInfo->commandPool;
-        }
-    }
-
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
-                                                      VkDescriptorSet *pDescriptorSets) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
-    VkResult result;
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, device);
-        startWriteObject(my_data, pAllocateInfo->descriptorPool);
-        // Host access to pAllocateInfo::descriptorPool must be externally synchronized
-    }
-    result = pTable->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
-    if (threadChecks) {
-        finishReadObject(my_data, device);
-        finishWriteObject(my_data, pAllocateInfo->descriptorPool);
-        // Host access to pAllocateInfo::descriptorPool must be externally synchronized
-    } else {
-        finishMultiThread();
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
-                                              const VkCommandBuffer *pCommandBuffers) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
-    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
-    const bool lockCommandPool = false;  // pool is already directly locked
-    bool threadChecks = startMultiThread();
-    if (threadChecks) {
-        startReadObject(my_data, device);
-        startWriteObject(my_data, commandPool);
-        for (uint32_t index = 0; index < commandBufferCount; index++) {
-            startWriteObject(my_data, pCommandBuffers[index], lockCommandPool);
-        }
-        // The driver may immediately reuse command buffers in another thread.
-        // These updates need to be done before calling down to the driver.
-        for (uint32_t index = 0; index < commandBufferCount; index++) {
-            finishWriteObject(my_data, pCommandBuffers[index], lockCommandPool);
-            std::lock_guard<std::mutex> lock(command_pool_lock);
-            command_pool_map.erase(pCommandBuffers[index]);
-        }
-    }
-
-    pTable->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
-    if (threadChecks) {
-        finishReadObject(my_data, device);
-        finishWriteObject(my_data, commandPool);
-    } else {
-        finishMultiThread();
-    }
-}
-
-}  // namespace threading
-
-// vk_layer_logging.h expects these to be defined
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                              const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugUtilsMessengerEXT *pMessenger) {
-    return threading::CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    threading::DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-                                                        VkDebugUtilsMessageTypeFlagsEXT messageTypes,
-                                                        const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
-    threading::SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
-                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugReportCallbackEXT *pMsgCallback) {
-    return threading::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    threading::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    threading::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-}
-
-// loader-layer interface v0, just wrappers since there is only a layer
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                                      VkExtensionProperties *pProperties) {
-    return threading::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
-                                                                                  VkLayerProperties *pProperties) {
-    return threading::EnumerateInstanceLayerProperties(pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                                VkLayerProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return threading::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                                                                    const char *pLayerName, uint32_t *pCount,
-                                                                                    VkExtensionProperties *pProperties) {
-    // the layer command handles VK_NULL_HANDLE just fine internally
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return threading::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
-    return threading::GetDeviceProcAddr(dev, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    return threading::GetInstanceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
-                                                                                           const char *funcName) {
-    return threading::GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
-    assert(pVersionStruct != NULL);
-    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
-
-    // Fill in the function pointers if our version is at least capable of having the structure contain them.
-    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
-        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
-        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
-        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
-    }
-
-    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        threading::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
-    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-    }
-
-    return VK_SUCCESS;
-}
diff --git a/layers/threading.h b/layers/threading.h
deleted file mode 100644
index 4404692..0000000
--- a/layers/threading.h
+++ /dev/null
@@ -1,445 +0,0 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Author: Cody Northrop <cody@lunarg.com>
- * Author: Mike Stroyan <mike@LunarG.com>
- */
-
-#ifndef THREADING_H
-#define THREADING_H
-#include <condition_variable>
-#include <mutex>
-#include <vector>
-#include <unordered_set>
-#include <string>
-#include "vk_layer_config.h"
-#include "vk_layer_logging.h"
-
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(DISTINCT_NONDISPATCHABLE_PHONY_HANDLE)
-// The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE
-#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \
-    defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
-// If pointers are 64-bit, then there can be separate counters for each
-// NONDISPATCHABLE_HANDLE type.  Otherwise they are all typedef uint64_t.
-#define DISTINCT_NONDISPATCHABLE_HANDLES
-// Make sure we catch any disagreement between us and the vulkan definition
-static_assert(std::is_pointer<DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value,
-              "Mismatched non-dispatchable handle handle, expected pointer type.");
-#else
-// Make sure we catch any disagreement between us and the vulkan definition
-static_assert(std::is_same<uint64_t, DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value,
-              "Mismatched non-dispatchable handle handle, expected uint64_t.");
-#endif
-
-// Suppress unused warning on Linux
-#if defined(__GNUC__)
-#define DECORATE_UNUSED __attribute__((unused))
-#else
-#define DECORATE_UNUSED
-#endif
-
-// clang-format off
-static const char DECORATE_UNUSED *kVUID_Threading_Info = "UNASSIGNED-Threading-Info";
-static const char DECORATE_UNUSED *kVUID_Threading_MultipleThreads = "UNASSIGNED-Threading-MultipleThreads";
-static const char DECORATE_UNUSED *kVUID_Threading_SingleThreadReuse = "UNASSIGNED-Threading-SingleThreadReuse";
-// clang-format on
-
-#undef DECORATE_UNUSED
-
-struct object_use_data {
-    loader_platform_thread_id thread;
-    int reader_count;
-    int writer_count;
-};
-
-struct layer_data;
-
-namespace threading {
-volatile bool vulkan_in_use = false;
-volatile bool vulkan_multi_threaded = false;
-// starting check if an application is using vulkan from multiple threads.
-inline bool startMultiThread() {
-    if (vulkan_multi_threaded) {
-        return true;
-    }
-    if (vulkan_in_use) {
-        vulkan_multi_threaded = true;
-        return true;
-    }
-    vulkan_in_use = true;
-    return false;
-}
-
-// finishing check if an application is using vulkan from multiple threads.
-inline void finishMultiThread() { vulkan_in_use = false; }
-}  // namespace threading
-
-template <typename T>
-class counter {
-   public:
-    const char *typeName;
-    VkDebugReportObjectTypeEXT objectType;
-    std::unordered_map<T, object_use_data> uses;
-    std::mutex counter_lock;
-    std::condition_variable counter_condition;
-    void startWrite(debug_report_data *report_data, T object) {
-        if (object == VK_NULL_HANDLE) {
-            return;
-        }
-        bool skipCall = false;
-        loader_platform_thread_id tid = loader_platform_get_thread_id();
-        std::unique_lock<std::mutex> lock(counter_lock);
-        if (uses.find(object) == uses.end()) {
-            // There is no current use of the object.  Record writer thread.
-            struct object_use_data *use_data = &uses[object];
-            use_data->reader_count = 0;
-            use_data->writer_count = 1;
-            use_data->thread = tid;
-        } else {
-            struct object_use_data *use_data = &uses[object];
-            if (use_data->reader_count == 0) {
-                // There are no readers.  Two writers just collided.
-                if (use_data->thread != tid) {
-                    skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object),
-                                        kVUID_Threading_MultipleThreads,
-                                        "THREADING ERROR : object of type %s is simultaneously used in "
-                                        "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
-                                        typeName, (uint64_t)use_data->thread, (uint64_t)tid);
-                    if (skipCall) {
-                        // Wait for thread-safe access to object instead of skipping call.
-                        while (uses.find(object) != uses.end()) {
-                            counter_condition.wait(lock);
-                        }
-                        // There is now no current use of the object.  Record writer thread.
-                        struct object_use_data *new_use_data = &uses[object];
-                        new_use_data->thread = tid;
-                        new_use_data->reader_count = 0;
-                        new_use_data->writer_count = 1;
-                    } else {
-                        // Continue with an unsafe use of the object.
-                        use_data->thread = tid;
-                        use_data->writer_count += 1;
-                    }
-                } else {
-                    // This is either safe multiple use in one call, or recursive use.
-                    // There is no way to make recursion safe.  Just forge ahead.
-                    use_data->writer_count += 1;
-                }
-            } else {
-                // There are readers.  This writer collided with them.
-                if (use_data->thread != tid) {
-                    skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object),
-                                        kVUID_Threading_MultipleThreads,
-                                        "THREADING ERROR : object of type %s is simultaneously used in "
-                                        "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
-                                        typeName, (uint64_t)use_data->thread, (uint64_t)tid);
-                    if (skipCall) {
-                        // Wait for thread-safe access to object instead of skipping call.
-                        while (uses.find(object) != uses.end()) {
-                            counter_condition.wait(lock);
-                        }
-                        // There is now no current use of the object.  Record writer thread.
-                        struct object_use_data *new_use_data = &uses[object];
-                        new_use_data->thread = tid;
-                        new_use_data->reader_count = 0;
-                        new_use_data->writer_count = 1;
-                    } else {
-                        // Continue with an unsafe use of the object.
-                        use_data->thread = tid;
-                        use_data->writer_count += 1;
-                    }
-                } else {
-                    // This is either safe multiple use in one call, or recursive use.
-                    // There is no way to make recursion safe.  Just forge ahead.
-                    use_data->writer_count += 1;
-                }
-            }
-        }
-    }
-
-    void finishWrite(T object) {
-        if (object == VK_NULL_HANDLE) {
-            return;
-        }
-        // Object is no longer in use
-        std::unique_lock<std::mutex> lock(counter_lock);
-        uses[object].writer_count -= 1;
-        if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) {
-            uses.erase(object);
-        }
-        // Notify any waiting threads that this object may be safe to use
-        lock.unlock();
-        counter_condition.notify_all();
-    }
-
-    void startRead(debug_report_data *report_data, T object) {
-        if (object == VK_NULL_HANDLE) {
-            return;
-        }
-        bool skipCall = false;
-        loader_platform_thread_id tid = loader_platform_get_thread_id();
-        std::unique_lock<std::mutex> lock(counter_lock);
-        if (uses.find(object) == uses.end()) {
-            // There is no current use of the object.  Record reader count
-            struct object_use_data *use_data = &uses[object];
-            use_data->reader_count = 1;
-            use_data->writer_count = 0;
-            use_data->thread = tid;
-        } else if (uses[object].writer_count > 0 && uses[object].thread != tid) {
-            // There is a writer of the object.
-            skipCall |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), kVUID_Threading_MultipleThreads,
-                        "THREADING ERROR : object of type %s is simultaneously used in "
-                        "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
-                        typeName, (uint64_t)uses[object].thread, (uint64_t)tid);
-            if (skipCall) {
-                // Wait for thread-safe access to object instead of skipping call.
-                while (uses.find(object) != uses.end()) {
-                    counter_condition.wait(lock);
-                }
-                // There is no current use of the object.  Record reader count
-                struct object_use_data *use_data = &uses[object];
-                use_data->reader_count = 1;
-                use_data->writer_count = 0;
-                use_data->thread = tid;
-            } else {
-                uses[object].reader_count += 1;
-            }
-        } else {
-            // There are other readers of the object.  Increase reader count
-            uses[object].reader_count += 1;
-        }
-    }
-    void finishRead(T object) {
-        if (object == VK_NULL_HANDLE) {
-            return;
-        }
-        std::unique_lock<std::mutex> lock(counter_lock);
-        uses[object].reader_count -= 1;
-        if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) {
-            uses.erase(object);
-        }
-        // Notify any waiting threads that this object may be safe to use
-        lock.unlock();
-        counter_condition.notify_all();
-    }
-    counter(const char *name = "", VkDebugReportObjectTypeEXT type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) {
-        typeName = name;
-        objectType = type;
-    }
-};
-
-struct layer_data {
-    VkInstance instance;
-
-    debug_report_data *report_data;
-    std::vector<VkDebugReportCallbackEXT> logging_callback;
-    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
-    VkLayerDispatchTable *device_dispatch_table;
-    VkLayerInstanceDispatchTable *instance_dispatch_table;
-    std::unordered_set<std::string> device_extension_set;
-
-    // The following are for keeping track of the temporary callbacks that can
-    // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_report_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
-    VkDebugReportCallbackEXT *tmp_report_callbacks;
-    uint32_t num_tmp_debug_messengers;
-    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
-    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
-
-    counter<VkCommandBuffer> c_VkCommandBuffer;
-    counter<VkDevice> c_VkDevice;
-    counter<VkInstance> c_VkInstance;
-    counter<VkQueue> c_VkQueue;
-#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
-    counter<VkBuffer> c_VkBuffer;
-    counter<VkBufferView> c_VkBufferView;
-    counter<VkCommandPool> c_VkCommandPool;
-    counter<VkDescriptorPool> c_VkDescriptorPool;
-    counter<VkDescriptorSet> c_VkDescriptorSet;
-    counter<VkDescriptorSetLayout> c_VkDescriptorSetLayout;
-    counter<VkDeviceMemory> c_VkDeviceMemory;
-    counter<VkEvent> c_VkEvent;
-    counter<VkFence> c_VkFence;
-    counter<VkFramebuffer> c_VkFramebuffer;
-    counter<VkImage> c_VkImage;
-    counter<VkImageView> c_VkImageView;
-    counter<VkPipeline> c_VkPipeline;
-    counter<VkPipelineCache> c_VkPipelineCache;
-    counter<VkPipelineLayout> c_VkPipelineLayout;
-    counter<VkQueryPool> c_VkQueryPool;
-    counter<VkRenderPass> c_VkRenderPass;
-    counter<VkSampler> c_VkSampler;
-    counter<VkSemaphore> c_VkSemaphore;
-    counter<VkShaderModule> c_VkShaderModule;
-    counter<VkDebugReportCallbackEXT> c_VkDebugReportCallbackEXT;
-    counter<VkObjectTableNVX> c_VkObjectTableNVX;
-    counter<VkIndirectCommandsLayoutNVX> c_VkIndirectCommandsLayoutNVX;
-    counter<VkDisplayKHR> c_VkDisplayKHR;
-    counter<VkDisplayModeKHR> c_VkDisplayModeKHR;
-    counter<VkSurfaceKHR> c_VkSurfaceKHR;
-    counter<VkSwapchainKHR> c_VkSwapchainKHR;
-    counter<VkDescriptorUpdateTemplateKHR> c_VkDescriptorUpdateTemplateKHR;
-    counter<VkValidationCacheEXT> c_VkValidationCacheEXT;
-    counter<VkSamplerYcbcrConversionKHR> c_VkSamplerYcbcrConversionKHR;
-    counter<VkDebugUtilsMessengerEXT> c_VkDebugUtilsMessengerEXT;
-    counter<VkAccelerationStructureNVX> c_VkAccelerationStructureNVX;
-#else   // DISTINCT_NONDISPATCHABLE_HANDLES
-    counter<uint64_t> c_uint64_t;
-#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
-
-    layer_data()
-        : report_data(nullptr),
-          num_tmp_report_callbacks(0),
-          tmp_report_create_infos(nullptr),
-          tmp_report_callbacks(nullptr),
-          num_tmp_debug_messengers(0),
-          tmp_messenger_create_infos(nullptr),
-          tmp_debug_messengers(nullptr),
-          c_VkCommandBuffer("VkCommandBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT),
-          c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT),
-          c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT),
-          c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT),
-#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
-          c_VkBuffer("VkBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT),
-          c_VkBufferView("VkBufferView", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT),
-          c_VkCommandPool("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT),
-          c_VkDescriptorPool("VkDescriptorPool", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT),
-          c_VkDescriptorSet("VkDescriptorSet", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT),
-          c_VkDescriptorSetLayout("VkDescriptorSetLayout", VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT),
-          c_VkDeviceMemory("VkDeviceMemory", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT),
-          c_VkEvent("VkEvent", VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT),
-          c_VkFence("VkFence", VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT),
-          c_VkFramebuffer("VkFramebuffer", VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT),
-          c_VkImage("VkImage", VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT),
-          c_VkImageView("VkImageView", VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT),
-          c_VkPipeline("VkPipeline", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT),
-          c_VkPipelineCache("VkPipelineCache", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT),
-          c_VkPipelineLayout("VkPipelineLayout", VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT),
-          c_VkQueryPool("VkQueryPool", VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT),
-          c_VkRenderPass("VkRenderPass", VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT),
-          c_VkSampler("VkSampler", VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT),
-          c_VkSemaphore("VkSemaphore", VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT),
-          c_VkShaderModule("VkShaderModule", VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT),
-          c_VkDebugReportCallbackEXT("VkDebugReportCallbackEXT", VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT),
-          c_VkObjectTableNVX("VkObjectTableNVX", VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT),
-          c_VkIndirectCommandsLayoutNVX("VkIndirectCommandsLayoutNVX",
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT),
-          c_VkDisplayKHR("VkDisplayKHR", VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT),
-          c_VkDisplayModeKHR("VkDisplayModeKHR", VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT),
-          c_VkSurfaceKHR("VkSurfaceKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT),
-          c_VkSwapchainKHR("VkSwapchainKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT),
-          c_VkDescriptorUpdateTemplateKHR("VkDescriptorUpdateTemplateKHR",
-                                          VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT),
-          c_VkSamplerYcbcrConversionKHR("VkSamplerYcbcrConversionKHR",
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT),
-          c_VkDebugUtilsMessengerEXT("VkDebugUtilsMessengerEXT", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT),
-          c_VkAccelerationStructureNVX("VkAccelerationStructureNVX", VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT)
-#else   // DISTINCT_NONDISPATCHABLE_HANDLES
-          c_uint64_t("NON_DISPATCHABLE_HANDLE", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT)
-#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
-              {};
-};
-
-#define WRAPPER(type)                                                                                                 \
-    static void startWriteObject(struct layer_data *my_data, type object) {                                           \
-        my_data->c_##type.startWrite(my_data->report_data, object);                                                   \
-    }                                                                                                                 \
-    static void finishWriteObject(struct layer_data *my_data, type object) { my_data->c_##type.finishWrite(object); } \
-    static void startReadObject(struct layer_data *my_data, type object) {                                            \
-        my_data->c_##type.startRead(my_data->report_data, object);                                                    \
-    }                                                                                                                 \
-    static void finishReadObject(struct layer_data *my_data, type object) { my_data->c_##type.finishRead(object); }
-
-WRAPPER(VkDevice)
-WRAPPER(VkInstance)
-WRAPPER(VkQueue)
-#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
-WRAPPER(VkBuffer)
-WRAPPER(VkBufferView)
-WRAPPER(VkCommandPool)
-WRAPPER(VkDescriptorPool)
-WRAPPER(VkDescriptorSet)
-WRAPPER(VkDescriptorSetLayout)
-WRAPPER(VkDeviceMemory)
-WRAPPER(VkEvent)
-WRAPPER(VkFence)
-WRAPPER(VkFramebuffer)
-WRAPPER(VkImage)
-WRAPPER(VkImageView)
-WRAPPER(VkPipeline)
-WRAPPER(VkPipelineCache)
-WRAPPER(VkPipelineLayout)
-WRAPPER(VkQueryPool)
-WRAPPER(VkRenderPass)
-WRAPPER(VkSampler)
-WRAPPER(VkSemaphore)
-WRAPPER(VkShaderModule)
-WRAPPER(VkDebugReportCallbackEXT)
-WRAPPER(VkObjectTableNVX)
-WRAPPER(VkIndirectCommandsLayoutNVX)
-WRAPPER(VkDisplayKHR)
-WRAPPER(VkDisplayModeKHR)
-WRAPPER(VkSurfaceKHR)
-WRAPPER(VkSwapchainKHR)
-WRAPPER(VkDescriptorUpdateTemplateKHR)
-WRAPPER(VkValidationCacheEXT)
-WRAPPER(VkSamplerYcbcrConversionKHR)
-WRAPPER(VkDebugUtilsMessengerEXT)
-WRAPPER(VkAccelerationStructureNVX)
-#else   // DISTINCT_NONDISPATCHABLE_HANDLES
-WRAPPER(uint64_t)
-#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
-
-static std::unordered_map<void *, layer_data *> layer_data_map;
-static std::mutex command_pool_lock;
-static std::unordered_map<VkCommandBuffer, VkCommandPool> command_pool_map;
-
-// VkCommandBuffer needs check for implicit use of command pool
-static void startWriteObject(struct layer_data *my_data, VkCommandBuffer object, bool lockPool = true) {
-    if (lockPool) {
-        std::unique_lock<std::mutex> lock(command_pool_lock);
-        VkCommandPool pool = command_pool_map[object];
-        lock.unlock();
-        startWriteObject(my_data, pool);
-    }
-    my_data->c_VkCommandBuffer.startWrite(my_data->report_data, object);
-}
-static void finishWriteObject(struct layer_data *my_data, VkCommandBuffer object, bool lockPool = true) {
-    my_data->c_VkCommandBuffer.finishWrite(object);
-    if (lockPool) {
-        std::unique_lock<std::mutex> lock(command_pool_lock);
-        VkCommandPool pool = command_pool_map[object];
-        lock.unlock();
-        finishWriteObject(my_data, pool);
-    }
-}
-static void startReadObject(struct layer_data *my_data, VkCommandBuffer object) {
-    std::unique_lock<std::mutex> lock(command_pool_lock);
-    VkCommandPool pool = command_pool_map[object];
-    lock.unlock();
-    startReadObject(my_data, pool);
-    my_data->c_VkCommandBuffer.startRead(my_data->report_data, object);
-}
-static void finishReadObject(struct layer_data *my_data, VkCommandBuffer object) {
-    my_data->c_VkCommandBuffer.finishRead(object);
-    std::unique_lock<std::mutex> lock(command_pool_lock);
-    VkCommandPool pool = command_pool_map[object];
-    lock.unlock();
-    finishReadObject(my_data, pool);
-}
-#endif  // THREADING_H
diff --git a/layers/unique_objects.cpp b/layers/unique_objects.cpp
deleted file mode 100644
index 0cf31fc..0000000
--- a/layers/unique_objects.cpp
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (c) 2015-2018 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Author: Tobin Ehlis <tobine@google.com>
- * Author: Mark Lobodzinski <mark@lunarg.com>
- */
-
-#define NOMINMAX
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unordered_map>
-#include <vector>
-#include <list>
-#include <memory>
-#include <algorithm>
-
-// For Windows, this #include must come before other Vk headers.
-#include "vk_loader_platform.h"
-
-#include "unique_objects.h"
-#include "vk_dispatch_table_helper.h"
-#include "vk_layer_config.h"
-#include "vk_layer_data.h"
-#include "vk_layer_extension_utils.h"
-#include "vk_layer_logging.h"
-#include "vk_layer_utils.h"
-#include "vk_enum_string_helper.h"
-#include "vk_object_types.h"
-#include "vk_extension_helper.h"
-#include "vulkan/vk_layer.h"
-
-// This intentionally includes a cpp file
-#include "vk_safe_struct.cpp"
-
-#include "unique_objects_wrappers.h"
-
-using mutex_t = std::mutex;
-using lock_guard_t = std::lock_guard<mutex_t>;
-
-namespace unique_objects {
-
-static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-
-static void initUniqueObjects(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "google_unique_objects");
-    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
-                                  "google_unique_objects");
-}
-
-// Check enabled instance extensions against supported instance extension whitelist
-static void InstanceExtensionWhitelist(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-
-    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        // Check for recognized instance extensions
-        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kInstanceExtensionNames)) {
-            log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUIDUndefined,
-                    "Instance Extension %s is not supported by this layer.  Using this extension may adversely affect validation "
-                    "results and/or produce undefined behavior.",
-                    pCreateInfo->ppEnabledExtensionNames[i]);
-        }
-    }
-}
-
-// Check enabled device extensions against supported device extension whitelist
-static void DeviceExtensionWhitelist(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-
-    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        // Check for recognized device extensions
-        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kDeviceExtensionNames)) {
-            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    kVUIDUndefined,
-                    "Device Extension %s is not supported by this layer.  Using this extension may adversely affect validation "
-                    "results and/or produce undefined behavior.",
-                    pCreateInfo->ppEnabledExtensionNames[i]);
-        }
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                                              VkInstance *pInstance) {
-    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
-    if (fpCreateInstance == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
-    instance_data->instance = *pInstance;
-    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
-
-    instance_data->instance = *pInstance;
-    instance_data->report_data = debug_utils_create_instance(
-        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
-
-    // Set up temporary debug callbacks to output messages at CreateInstance-time
-    if (!layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &instance_data->num_tmp_debug_messengers,
-                                         &instance_data->tmp_messenger_create_infos, &instance_data->tmp_debug_messengers)) {
-        if (instance_data->num_tmp_debug_messengers > 0) {
-            if (layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                                  instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers)) {
-                layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
-                instance_data->num_tmp_debug_messengers = 0;
-            }
-        }
-    }
-    if (!layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_report_callbacks,
-                                         &instance_data->tmp_report_create_infos, &instance_data->tmp_report_callbacks)) {
-        if (instance_data->num_tmp_report_callbacks > 0) {
-            if (layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                                  instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks)) {
-                layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
-                instance_data->num_tmp_report_callbacks = 0;
-            }
-        }
-    }
-
-    initUniqueObjects(instance_data, pAllocator);
-    InstanceExtensionWhitelist(pCreateInfo, *pInstance);
-
-    // Disable and free tmp callbacks, no longer necessary
-    if (instance_data->num_tmp_debug_messengers > 0) {
-        layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
-                                           instance_data->tmp_debug_messengers);
-        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
-        instance_data->num_tmp_debug_messengers = 0;
-    }
-    if (instance_data->num_tmp_report_callbacks > 0) {
-        layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
-                                           instance_data->tmp_report_callbacks);
-        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
-        instance_data->num_tmp_report_callbacks = 0;
-    }
-
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(instance);
-    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
-    VkLayerInstanceDispatchTable *disp_table = &instance_data->dispatch_table;
-    disp_table->DestroyInstance(instance, pAllocator);
-
-    // Clean up logging callback, if any
-    while (instance_data->logging_messenger.size() > 0) {
-        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
-        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-        instance_data->logging_messenger.pop_back();
-    }
-    while (instance_data->logging_callback.size() > 0) {
-        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
-        instance_data->logging_callback.pop_back();
-    }
-
-    layer_debug_utils_destroy_instance(instance_data->report_data);
-    FreeLayerDataPtr(key, instance_layer_data_map);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
-                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
-    instance_layer_data *my_instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
-    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
-
-    assert(chain_info->u.pLayerInfo);
-    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
-    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
-    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
-    if (fpCreateDevice == NULL) {
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    // Advance the link info for the next element on the chain
-    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
-
-    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
-    if (result != VK_SUCCESS) {
-        return result;
-    }
-
-    layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-    my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
-
-    // Setup layer's device dispatch table
-    layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
-    // Save pCreateInfo device extension list for GetDeviceProcAddr()
-    for (uint32_t extn = 0; extn < pCreateInfo->enabledExtensionCount; extn++) {
-        my_device_data->device_extension_set.insert(pCreateInfo->ppEnabledExtensionNames[extn]);
-    }
-
-    DeviceExtensionWhitelist(pCreateInfo, *pDevice);
-
-    // Set gpu for this device in order to get at any objects mapped at instance level
-    my_device_data->instance_data = my_instance_data;
-
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
-
-    layer_debug_utils_destroy_device(device);
-    dev_data->dispatch_table.DestroyDevice(device, pAllocator);
-
-    FreeLayerDataPtr(key, layer_data_map);
-}
-
-static const VkLayerProperties globalLayerProps = {"VK_LAYER_GOOGLE_unique_objects",
-                                                   VK_LAYER_API_VERSION,  // specVersion
-                                                   1,                     // implementationVersion
-                                                   "Google Validation Layer"};
-
-/// Declare prototype for these functions
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                              VkLayerProperties *pProperties) {
-    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                    VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))
-        return util_GetExtensionProperties(0, NULL, pCount, pProperties);
-
-    return VK_ERROR_LAYER_NOT_PRESENT;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
-                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
-    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))
-        return util_GetExtensionProperties(0, nullptr, pCount, pProperties);
-
-    assert(physicalDevice);
-
-    dispatch_key key = get_dispatch_key(physicalDevice);
-    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
-    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    if (!ApiParentExtensionEnabled(funcName, device_data->device_extension_set)) {
-        return nullptr;
-    }
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-    const auto &table = device_data->dispatch_table;
-    if (!table.GetDeviceProcAddr) return nullptr;
-    return table.GetDeviceProcAddr(device, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    const auto item = name_to_funcptr_map.find(funcName);
-    if (item != name_to_funcptr_map.end()) {
-        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
-    }
-
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    const auto &table = instance_data->dispatch_table;
-    if (!table.GetInstanceProcAddr) return nullptr;
-    return table.GetInstanceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkLayerInstanceDispatchTable *disp_table = &instance_data->dispatch_table;
-    if (disp_table->GetPhysicalDeviceProcAddr == NULL) {
-        return NULL;
-    }
-    return disp_table->GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                                      const VkComputePipelineCreateInfo *pCreateInfos,
-                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkComputePipelineCreateInfo *local_pCreateInfos = NULL;
-    if (pCreateInfos) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        local_pCreateInfos = new safe_VkComputePipelineCreateInfo[createInfoCount];
-        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
-            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]);
-            if (pCreateInfos[idx0].basePipelineHandle) {
-                local_pCreateInfos[idx0].basePipelineHandle = Unwrap(pCreateInfos[idx0].basePipelineHandle);
-            }
-            if (pCreateInfos[idx0].layout) {
-                local_pCreateInfos[idx0].layout = Unwrap(pCreateInfos[idx0].layout);
-            }
-            if (pCreateInfos[idx0].stage.module) {
-                local_pCreateInfos[idx0].stage.module = Unwrap(pCreateInfos[idx0].stage.module);
-            }
-        }
-    }
-    if (pipelineCache) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        pipelineCache = Unwrap(pipelineCache);
-    }
-
-    VkResult result = device_data->dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount,
-                                                                         local_pCreateInfos->ptr(), pAllocator, pPipelines);
-    delete[] local_pCreateInfos;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < createInfoCount; ++i) {
-            if (pPipelines[i] != VK_NULL_HANDLE) {
-                pPipelines[i] = WrapNew(pPipelines[i]);
-            }
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
-                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = nullptr;
-    if (pCreateInfos) {
-        local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount];
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
-            bool uses_color_attachment = false;
-            bool uses_depthstencil_attachment = false;
-            {
-                const auto subpasses_uses_it = device_data->renderpasses_states.find(Unwrap(pCreateInfos[idx0].renderPass));
-                if (subpasses_uses_it != device_data->renderpasses_states.end()) {
-                    const auto &subpasses_uses = subpasses_uses_it->second;
-                    if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[idx0].subpass))
-                        uses_color_attachment = true;
-                    if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[idx0].subpass))
-                        uses_depthstencil_attachment = true;
-                }
-            }
-
-            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0], uses_color_attachment, uses_depthstencil_attachment);
-
-            if (pCreateInfos[idx0].basePipelineHandle) {
-                local_pCreateInfos[idx0].basePipelineHandle = Unwrap(pCreateInfos[idx0].basePipelineHandle);
-            }
-            if (pCreateInfos[idx0].layout) {
-                local_pCreateInfos[idx0].layout = Unwrap(pCreateInfos[idx0].layout);
-            }
-            if (pCreateInfos[idx0].pStages) {
-                for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) {
-                    if (pCreateInfos[idx0].pStages[idx1].module) {
-                        local_pCreateInfos[idx0].pStages[idx1].module = Unwrap(pCreateInfos[idx0].pStages[idx1].module);
-                    }
-                }
-            }
-            if (pCreateInfos[idx0].renderPass) {
-                local_pCreateInfos[idx0].renderPass = Unwrap(pCreateInfos[idx0].renderPass);
-            }
-        }
-    }
-    if (pipelineCache) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        pipelineCache = Unwrap(pipelineCache);
-    }
-
-    VkResult result = device_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, createInfoCount,
-                                                                          local_pCreateInfos->ptr(), pAllocator, pPipelines);
-    delete[] local_pCreateInfos;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < createInfoCount; ++i) {
-            if (pPipelines[i] != VK_NULL_HANDLE) {
-                pPipelines[i] = WrapNew(pPipelines[i]);
-            }
-        }
-    }
-    return result;
-}
-
-template <typename T>
-static void PostCallCreateRenderPass(layer_data *dev_data, const T *pCreateInfo, VkRenderPass renderPass) {
-    auto &renderpass_state = dev_data->renderpasses_states[renderPass];
-
-    for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
-        bool uses_color = false;
-        for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
-            if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
-
-        bool uses_depthstencil = false;
-        if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
-            if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
-                uses_depthstencil = true;
-
-        if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
-        if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
-    }
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
-                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-
-        PostCallCreateRenderPass(dev_data, pCreateInfo, *pRenderPass);
-
-        *pRenderPass = WrapNew(*pRenderPass);
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
-                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkResult result = dev_data->dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-
-        PostCallCreateRenderPass(dev_data, pCreateInfo, *pRenderPass);
-
-        *pRenderPass = WrapNew(*pRenderPass);
-    }
-    return result;
-}
-
-static void PostCallDestroyRenderPass(layer_data *dev_data, VkRenderPass renderPass) {
-    dev_data->renderpasses_states.erase(renderPass);
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    uint64_t renderPass_id = reinterpret_cast<uint64_t &>(renderPass);
-    renderPass = (VkRenderPass)unique_id_mapping[renderPass_id];
-    unique_id_mapping.erase(renderPass_id);
-    lock.unlock();
-    dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
-
-    lock.lock();
-    PostCallDestroyRenderPass(dev_data, renderPass);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
-                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
-    layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkSwapchainCreateInfoKHR *local_pCreateInfo = NULL;
-    if (pCreateInfo) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        local_pCreateInfo = new safe_VkSwapchainCreateInfoKHR(pCreateInfo);
-        local_pCreateInfo->oldSwapchain = Unwrap(pCreateInfo->oldSwapchain);
-        // Surface is instance-level object
-        local_pCreateInfo->surface = Unwrap(pCreateInfo->surface);
-    }
-
-    VkResult result = my_map_data->dispatch_table.CreateSwapchainKHR(device, local_pCreateInfo->ptr(), pAllocator, pSwapchain);
-    delete local_pCreateInfo;
-
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        *pSwapchain = WrapNew(*pSwapchain);
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
-                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
-                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkSwapchainCreateInfoKHR *local_pCreateInfos = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        if (pCreateInfos) {
-            local_pCreateInfos = new safe_VkSwapchainCreateInfoKHR[swapchainCount];
-            for (uint32_t i = 0; i < swapchainCount; ++i) {
-                local_pCreateInfos[i].initialize(&pCreateInfos[i]);
-                if (pCreateInfos[i].surface) {
-                    // Surface is instance-level object
-                    local_pCreateInfos[i].surface = Unwrap(pCreateInfos[i].surface);
-                }
-                if (pCreateInfos[i].oldSwapchain) {
-                    local_pCreateInfos[i].oldSwapchain = Unwrap(pCreateInfos[i].oldSwapchain);
-                }
-            }
-        }
-    }
-    VkResult result = dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, local_pCreateInfos->ptr(),
-                                                                         pAllocator, pSwapchains);
-    delete[] local_pCreateInfos;
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < swapchainCount; i++) {
-            pSwapchains[i] = WrapNew(pSwapchains[i]);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
-                                                     VkImage *pSwapchainImages) {
-    layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    VkSwapchainKHR wrapped_swapchain_handle = swapchain;
-    if (VK_NULL_HANDLE != swapchain) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        swapchain = Unwrap(swapchain);
-    }
-    VkResult result =
-        my_device_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
-    if ((VK_SUCCESS == result) || (VK_INCOMPLETE == result)) {
-        if ((*pSwapchainImageCount > 0) && pSwapchainImages) {
-            std::lock_guard<std::mutex> lock(global_lock);
-            auto &wrapped_swapchain_image_handles = my_device_data->swapchain_wrapped_image_handle_map[wrapped_swapchain_handle];
-            for (uint32_t i = static_cast<uint32_t>(wrapped_swapchain_image_handles.size()); i < *pSwapchainImageCount; i++) {
-                wrapped_swapchain_image_handles.emplace_back(WrapNew(pSwapchainImages[i]));
-            }
-            for (uint32_t i = 0; i < *pSwapchainImageCount; i++) {
-                pSwapchainImages[i] = wrapped_swapchain_image_handles[i];
-            }
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-
-    auto &image_array = dev_data->swapchain_wrapped_image_handle_map[swapchain];
-    for (auto &image_handle : image_array) {
-        unique_id_mapping.erase(HandleToUint64(image_handle));
-    }
-    dev_data->swapchain_wrapped_image_handle_map.erase(swapchain);
-
-    uint64_t swapchain_id = HandleToUint64(swapchain);
-    swapchain = (VkSwapchainKHR)unique_id_mapping[swapchain_id];
-    unique_id_mapping.erase(swapchain_id);
-    lock.unlock();
-    dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
-    safe_VkPresentInfoKHR *local_pPresentInfo = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        if (pPresentInfo) {
-            local_pPresentInfo = new safe_VkPresentInfoKHR(pPresentInfo);
-            if (local_pPresentInfo->pWaitSemaphores) {
-                for (uint32_t index1 = 0; index1 < local_pPresentInfo->waitSemaphoreCount; ++index1) {
-                    local_pPresentInfo->pWaitSemaphores[index1] = Unwrap(pPresentInfo->pWaitSemaphores[index1]);
-                }
-            }
-            if (local_pPresentInfo->pSwapchains) {
-                for (uint32_t index1 = 0; index1 < local_pPresentInfo->swapchainCount; ++index1) {
-                    local_pPresentInfo->pSwapchains[index1] = Unwrap(pPresentInfo->pSwapchains[index1]);
-                }
-            }
-        }
-    }
-    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, local_pPresentInfo->ptr());
-
-    // pResults is an output array embedded in a structure. The code generator neglects to copy back from the safe_* version,
-    // so handle it as a special case here:
-    if (pPresentInfo && pPresentInfo->pResults) {
-        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
-            pPresentInfo->pResults[i] = local_pPresentInfo->pResults[i];
-        }
-    }
-
-    delete local_pPresentInfo;
-    return result;
-}
-
-// This is the core version of this routine.  The extension version is below.
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplate(VkDevice device,
-                                                              const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        if (pCreateInfo) {
-            local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo);
-            if (pCreateInfo->descriptorSetLayout) {
-                local_create_info->descriptorSetLayout = Unwrap(pCreateInfo->descriptorSetLayout);
-            }
-            if (pCreateInfo->pipelineLayout) {
-                local_create_info->pipelineLayout = Unwrap(pCreateInfo->pipelineLayout);
-            }
-        }
-    }
-    VkResult result = dev_data->dispatch_table.CreateDescriptorUpdateTemplate(device, local_create_info->ptr(), pAllocator,
-                                                                              pDescriptorUpdateTemplate);
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        *pDescriptorUpdateTemplate = WrapNew(*pDescriptorUpdateTemplate);
-
-        // Shadow template createInfo for later updates
-        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
-        dev_data->desc_template_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state);
-    }
-    return result;
-}
-
-// This is the extension version of this routine.  The core version is above.
-VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
-                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
-                                                                 const VkAllocationCallbacks *pAllocator,
-                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        if (pCreateInfo) {
-            local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo);
-            if (pCreateInfo->descriptorSetLayout) {
-                local_create_info->descriptorSetLayout = Unwrap(pCreateInfo->descriptorSetLayout);
-            }
-            if (pCreateInfo->pipelineLayout) {
-                local_create_info->pipelineLayout = Unwrap(pCreateInfo->pipelineLayout);
-            }
-        }
-    }
-    VkResult result = dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, local_create_info->ptr(), pAllocator,
-                                                                                 pDescriptorUpdateTemplate);
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        *pDescriptorUpdateTemplate = WrapNew(*pDescriptorUpdateTemplate);
-
-        // Shadow template createInfo for later updates
-        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
-        dev_data->desc_template_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state);
-    }
-    return result;
-}
-
-// This is the core version of this routine.  The extension version is below.
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
-    dev_data->desc_template_map.erase(descriptor_update_template_id);
-    descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[descriptor_update_template_id];
-    unique_id_mapping.erase(descriptor_update_template_id);
-    lock.unlock();
-    dev_data->dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
-}
-
-// This is the extension version of this routine.  The core version is above.
-VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
-                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                              const VkAllocationCallbacks *pAllocator) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    std::unique_lock<std::mutex> lock(global_lock);
-    uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
-    dev_data->desc_template_map.erase(descriptor_update_template_id);
-    descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[descriptor_update_template_id];
-    unique_id_mapping.erase(descriptor_update_template_id);
-    lock.unlock();
-    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
-}
-
-void *BuildUnwrappedUpdateTemplateBuffer(layer_data *dev_data, uint64_t descriptorUpdateTemplate, const void *pData) {
-    auto const template_map_entry = dev_data->desc_template_map.find(descriptorUpdateTemplate);
-    if (template_map_entry == dev_data->desc_template_map.end()) {
-        assert(0);
-    }
-    auto const &create_info = template_map_entry->second->create_info;
-    size_t allocation_size = 0;
-    std::vector<std::tuple<size_t, VulkanObjectType, void *, size_t>> template_entries;
-
-    for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) {
-        for (uint32_t j = 0; j < create_info.pDescriptorUpdateEntries[i].descriptorCount; j++) {
-            size_t offset = create_info.pDescriptorUpdateEntries[i].offset + j * create_info.pDescriptorUpdateEntries[i].stride;
-            char *update_entry = (char *)(pData) + offset;
-
-            switch (create_info.pDescriptorUpdateEntries[i].descriptorType) {
-                case VK_DESCRIPTOR_TYPE_SAMPLER:
-                case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
-                case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
-                case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-                case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
-                    auto image_entry = reinterpret_cast<VkDescriptorImageInfo *>(update_entry);
-                    allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorImageInfo));
-
-                    VkDescriptorImageInfo *wrapped_entry = new VkDescriptorImageInfo(*image_entry);
-                    wrapped_entry->sampler = Unwrap(image_entry->sampler);
-                    wrapped_entry->imageView = Unwrap(image_entry->imageView);
-                    template_entries.emplace_back(offset, kVulkanObjectTypeImage, reinterpret_cast<void *>(wrapped_entry), 0);
-                } break;
-
-                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
-                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
-                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
-                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
-                    auto buffer_entry = reinterpret_cast<VkDescriptorBufferInfo *>(update_entry);
-                    allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorBufferInfo));
-
-                    VkDescriptorBufferInfo *wrapped_entry = new VkDescriptorBufferInfo(*buffer_entry);
-                    wrapped_entry->buffer = Unwrap(buffer_entry->buffer);
-                    template_entries.emplace_back(offset, kVulkanObjectTypeBuffer, reinterpret_cast<void *>(wrapped_entry), 0);
-                } break;
-
-                case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-                case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
-                    auto buffer_view_handle = reinterpret_cast<VkBufferView *>(update_entry);
-                    allocation_size = std::max(allocation_size, offset + sizeof(VkBufferView));
-
-                    VkBufferView wrapped_entry = Unwrap(*buffer_view_handle);
-                    template_entries.emplace_back(offset, kVulkanObjectTypeBufferView, reinterpret_cast<void *>(wrapped_entry), 0);
-                } break;
-                case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
-                    size_t numBytes = create_info.pDescriptorUpdateEntries[i].descriptorCount;
-                    allocation_size = std::max(allocation_size, offset + numBytes);
-                    // nothing to unwrap, just plain data
-                    template_entries.emplace_back(offset, kVulkanObjectTypeUnknown, reinterpret_cast<void *>(update_entry),
-                                                  numBytes);
-                    // to break out of the loop
-                    j = create_info.pDescriptorUpdateEntries[i].descriptorCount;
-                } break;
-                default:
-                    assert(0);
-                    break;
-            }
-        }
-    }
-    // Allocate required buffer size and populate with source/unwrapped data
-    void *unwrapped_data = malloc(allocation_size);
-    for (auto &this_entry : template_entries) {
-        VulkanObjectType type = std::get<1>(this_entry);
-        void *destination = (char *)unwrapped_data + std::get<0>(this_entry);
-        void *source = (char *)std::get<2>(this_entry);
-        size_t size = std::get<3>(this_entry);
-
-        if (size != 0) {
-            assert(type == kVulkanObjectTypeUnknown);
-            memcpy(destination, source, size);
-        } else {
-            switch (type) {
-                case kVulkanObjectTypeImage:
-                    *(reinterpret_cast<VkDescriptorImageInfo *>(destination)) =
-                        *(reinterpret_cast<VkDescriptorImageInfo *>(source));
-                    delete reinterpret_cast<VkDescriptorImageInfo *>(source);
-                    break;
-                case kVulkanObjectTypeBuffer:
-                    *(reinterpret_cast<VkDescriptorBufferInfo *>(destination)) =
-                        *(reinterpret_cast<VkDescriptorBufferInfo *>(source));
-                    delete reinterpret_cast<VkDescriptorBufferInfo *>(source);
-                    break;
-                case kVulkanObjectTypeBufferView:
-                    *(reinterpret_cast<VkBufferView *>(destination)) = reinterpret_cast<VkBufferView>(source);
-                    break;
-                default:
-                    assert(0);
-                    break;
-            }
-        }
-    }
-    return (void *)unwrapped_data;
-}
-
-// This is the core version of this routine.  The extension version is below.
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
-                                                           VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                           const void *pData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        descriptorSet = Unwrap(descriptorSet);
-        descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[template_handle];
-    }
-    void *unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(dev_data, template_handle, pData);
-    dev_data->dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer);
-    free(unwrapped_buffer);
-}
-
-// This is the extension version of this routine.  The core version is above.
-VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
-                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                              const void *pData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
-    void *unwrapped_buffer = nullptr;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        descriptorSet = Unwrap(descriptorSet);
-        descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[template_handle];
-        unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(dev_data, template_handle, pData);
-    }
-    dev_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer);
-    free(unwrapped_buffer);
-}
-
-VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
-                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
-                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
-    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
-    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
-    void *unwrapped_buffer = nullptr;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        descriptorUpdateTemplate = Unwrap(descriptorUpdateTemplate);
-        layout = Unwrap(layout);
-        unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(dev_data, template_handle, pData);
-    }
-    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set,
-                                                                 unwrapped_buffer);
-    free(unwrapped_buffer);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                     VkDisplayPropertiesKHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    VkResult result =
-        my_map_data->dispatch_table.GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            pProperties[idx0].display = MaybeWrapDisplay(pProperties[idx0].display, my_map_data);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                      VkDisplayProperties2KHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    VkResult result =
-        my_map_data->dispatch_table.GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            pProperties[idx0].displayProperties.display =
-                MaybeWrapDisplay(pProperties[idx0].displayProperties.display, my_map_data);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
-                                                                          VkDisplayPlanePropertiesKHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    VkResult result =
-        my_map_data->dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            VkDisplayKHR &opt_display = pProperties[idx0].currentDisplay;
-            if (opt_display) opt_display = MaybeWrapDisplay(opt_display, my_map_data);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,
-                                                                           uint32_t *pPropertyCount,
-                                                                           VkDisplayPlaneProperties2KHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-
-    VkResult result =
-        my_map_data->dispatch_table.GetPhysicalDeviceDisplayPlaneProperties2KHR(physicalDevice, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            VkDisplayKHR &opt_display = pProperties[idx0].displayPlaneProperties.currentDisplay;
-            if (opt_display) opt_display = MaybeWrapDisplay(opt_display, my_map_data);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
-                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    VkResult result =
-        my_map_data->dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pDisplays) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < *pDisplayCount; ++i) {
-            if (pDisplays[i]) pDisplays[i] = MaybeWrapDisplay(pDisplays[i], my_map_data);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
-                                                           uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        display = Unwrap(display);
-    }
-
-    VkResult result = my_map_data->dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            pProperties[idx0].displayMode = WrapNew(pProperties[idx0].displayMode);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
-                                                            uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties) {
-    instance_layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        display = Unwrap(display);
-    }
-
-    VkResult result =
-        my_map_data->dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties);
-    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
-            pProperties[idx0].displayModeProperties.displayMode = WrapNew(pProperties[idx0].displayModeProperties.displayMode);
-        }
-    }
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDebugMarkerObjectTagInfoEXT local_tag_info(pTagInfo);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.object));
-        if (it != unique_id_mapping.end()) {
-            local_tag_info.object = it->second;
-        }
-    }
-    VkResult result = device_data->dispatch_table.DebugMarkerSetObjectTagEXT(
-        device, reinterpret_cast<VkDebugMarkerObjectTagInfoEXT *>(&local_tag_info));
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL DebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDebugMarkerObjectNameInfoEXT local_name_info(pNameInfo);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.object));
-        if (it != unique_id_mapping.end()) {
-            local_name_info.object = it->second;
-        }
-    }
-    VkResult result = device_data->dispatch_table.DebugMarkerSetObjectNameEXT(
-        device, reinterpret_cast<VkDebugMarkerObjectNameInfoEXT *>(&local_name_info));
-    return result;
-}
-
-// VK_EXT_debug_utils
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDebugUtilsObjectTagInfoEXT local_tag_info(pTagInfo);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.objectHandle));
-        if (it != unique_id_mapping.end()) {
-            local_tag_info.objectHandle = it->second;
-        }
-    }
-    VkResult result = device_data->dispatch_table.SetDebugUtilsObjectTagEXT(
-        device, reinterpret_cast<const VkDebugUtilsObjectTagInfoEXT *>(&local_tag_info));
-    return result;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
-    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
-    safe_VkDebugUtilsObjectNameInfoEXT local_name_info(pNameInfo);
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.objectHandle));
-        if (it != unique_id_mapping.end()) {
-            local_name_info.objectHandle = it->second;
-        }
-    }
-    VkResult result = device_data->dispatch_table.SetDebugUtilsObjectNameEXT(
-        device, reinterpret_cast<const VkDebugUtilsObjectNameInfoEXT *>(&local_name_info));
-    return result;
-}
-
-// VK_EXT_debug_utils commands
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugUtilsMessengerEXT *pMessenger) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult result = instance_data->dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-
-    if (VK_SUCCESS == result) {
-        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
-    }
-    return result;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-    layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-                                                      VkDebugUtilsMessageTypeFlagsEXT messageTypes,
-                                                      const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
-}
-
-// VK_EXT_debug_report commands
-VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
-                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                            const VkAllocationCallbacks *pAllocator,
-                                                            VkDebugReportCallbackEXT *pMsgCallback) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-    if (VK_SUCCESS == res) {
-        lock_guard_t lock(global_lock);
-        res = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
-    }
-    return res;
-}
-
-VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                         const VkAllocationCallbacks *pAllocator) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-    lock_guard_t lock(global_lock);
-    layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
-    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-}
-
-}  // namespace unique_objects
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance,
-                                                              const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugUtilsMessengerEXT *pMessenger) {
-    return unique_objects::CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    unique_objects::DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-                                                        VkDebugUtilsMessageTypeFlagsEXT messageTypes,
-                                                        const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
-    unique_objects::SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
-                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                              const VkAllocationCallbacks *pAllocator,
-                                                              VkDebugReportCallbackEXT *pMsgCallback) {
-    return unique_objects::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
-                                                           const VkAllocationCallbacks *pAllocator) {
-    unique_objects::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-}
-
-VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    unique_objects::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
-                                                                                      VkExtensionProperties *pProperties) {
-    return unique_objects::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
-                                                                                  VkLayerProperties *pProperties) {
-    return unique_objects::EnumerateInstanceLayerProperties(pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
-                                                                                VkLayerProperties *pProperties) {
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return unique_objects::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
-    return unique_objects::GetDeviceProcAddr(dev, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
-    return unique_objects::GetInstanceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                                                                    const char *pLayerName, uint32_t *pCount,
-                                                                                    VkExtensionProperties *pProperties) {
-    assert(physicalDevice == VK_NULL_HANDLE);
-    return unique_objects::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
-                                                                                           const char *funcName) {
-    return unique_objects::GetPhysicalDeviceProcAddr(instance, funcName);
-}
-
-VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
-    assert(pVersionStruct != NULL);
-    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
-
-    // Fill in the function pointers if our version is at least capable of having the structure contain them.
-    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
-        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
-        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
-        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
-    }
-
-    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        unique_objects::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
-    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
-        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
-    }
-
-    return VK_SUCCESS;
-}
diff --git a/layers/unique_objects.h b/layers/unique_objects.h
deleted file mode 100644
index 753c5b2..0000000
--- a/layers/unique_objects.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
- * Copyright (C) 2015-2016 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Author: Tobin Ehlis <tobine@google.com>
- * Author: Mark Lobodzinski <mark@lunarg.com>
- */
-
-#include "vulkan/vulkan.h"
-
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "vk_layer_data.h"
-#include "vk_safe_struct.h"
-#include "vk_layer_utils.h"
-#include "mutex"
-
-#pragma once
-
-namespace unique_objects {
-
-// All increments must be guarded by global_lock
-static uint64_t global_unique_id = 1;
-static std::unordered_map<uint64_t, uint64_t> unique_id_mapping;  // Map uniqueID to actual object handle
-
-struct TEMPLATE_STATE {
-    VkDescriptorUpdateTemplateKHR desc_update_template;
-    safe_VkDescriptorUpdateTemplateCreateInfo create_info;
-
-    TEMPLATE_STATE(VkDescriptorUpdateTemplateKHR update_template, safe_VkDescriptorUpdateTemplateCreateInfo *pCreateInfo)
-        : desc_update_template(update_template), create_info(*pCreateInfo) {}
-};
-
-struct instance_layer_data {
-    VkInstance instance;
-
-    debug_report_data *report_data;
-    std::vector<VkDebugReportCallbackEXT> logging_callback;
-    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
-    VkLayerInstanceDispatchTable dispatch_table = {};
-    std::unordered_map<VkDisplayKHR, uint64_t> display_id_reverse_mapping;  // Reverse map display handles
-
-    // The following are for keeping track of the temporary callbacks that can
-    // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_report_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
-    VkDebugReportCallbackEXT *tmp_report_callbacks;
-    uint32_t num_tmp_debug_messengers;
-    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
-    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
-};
-
-struct layer_data {
-    instance_layer_data *instance_data;
-
-    debug_report_data *report_data;
-    VkLayerDispatchTable dispatch_table = {};
-
-    std::unordered_map<uint64_t, std::unique_ptr<TEMPLATE_STATE>> desc_template_map;
-    std::unordered_set<std::string> device_extension_set;
-
-    bool wsi_enabled;
-    VkPhysicalDevice gpu;
-
-    struct SubpassesUsageStates {
-        std::unordered_set<uint32_t> subpasses_using_color_attachment;
-        std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
-    };
-    // Uses unwrapped handles
-    std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
-
-    // Map of wrapped swapchain handles to arrays of wrapped swapchain image IDs
-    // Each swapchain has an immutable list of wrapped swapchain image IDs -- always return these IDs if they exist
-    std::unordered_map<VkSwapchainKHR, std::vector<VkImage>> swapchain_wrapped_image_handle_map;
-
-    layer_data() : wsi_enabled(false), gpu(VK_NULL_HANDLE){};
-};
-
-static std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;
-static std::unordered_map<void *, layer_data *> layer_data_map;
-
-static std::mutex global_lock;  // Protect map accesses and unique_id increments
-
-struct GenericHeader {
-    VkStructureType sType;
-    void *pNext;
-};
-
-template <typename T>
-bool ContainsExtStruct(const T *target, VkStructureType ext_type) {
-    assert(target != nullptr);
-
-    const GenericHeader *ext_struct = reinterpret_cast<const GenericHeader *>(target->pNext);
-
-    while (ext_struct != nullptr) {
-        if (ext_struct->sType == ext_type) {
-            return true;
-        }
-
-        ext_struct = reinterpret_cast<const GenericHeader *>(ext_struct->pNext);
-    }
-
-    return false;
-}
-
-/* Unwrap a handle. */
-// must hold lock!
-template <typename HandleType>
-HandleType Unwrap(HandleType wrappedHandle) {
-    // TODO: don't use operator[] here.
-    return (HandleType)unique_id_mapping[reinterpret_cast<uint64_t const &>(wrappedHandle)];
-}
-
-// Wrap a newly created handle with a new unique ID, and return the new ID -- must hold lock!
-template <typename HandleType>
-HandleType WrapNew(HandleType newlyCreatedHandle) {
-    auto unique_id = global_unique_id++;
-    unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
-    return (HandleType)unique_id;
-}
-
-// Specialized handling for VkDisplayKHR. Adds an entry to enable reverse-lookup.
-// must hold lock!
-VkDisplayKHR WrapDisplay(VkDisplayKHR newlyCreatedHandle, instance_layer_data *map_data) {
-    auto unique_id = global_unique_id++;
-    unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
-    map_data->display_id_reverse_mapping[newlyCreatedHandle] = unique_id;
-    return (VkDisplayKHR)unique_id;
-}
-
-// VkDisplayKHR objects don't have a single point of creation, so we need to see
-// if one already exists in the map before creating another.
-// must hold lock!
-VkDisplayKHR MaybeWrapDisplay(VkDisplayKHR handle, instance_layer_data *map_data) {
-    // See if this display is already known
-    auto it = map_data->display_id_reverse_mapping.find(handle);
-    if (it != map_data->display_id_reverse_mapping.end()) return (VkDisplayKHR)it->second;
-    // Unknown, so wrap
-    return WrapDisplay(handle, map_data);
-}
-
-}  // namespace unique_objects
diff --git a/layers/vk_format_utils.cpp b/layers/vk_format_utils.cpp
index f4c06c7..c4b9959 100644
--- a/layers/vk_format_utils.cpp
+++ b/layers/vk_format_utils.cpp
@@ -1,6 +1,6 @@
-/* Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
 #include "vk_format_utils.h"
 
 struct VULKAN_FORMAT_INFO {
-    size_t size;
+    uint32_t size;
     uint32_t channel_count;
     VkFormatCompatibilityClass format_class;
 };
@@ -35,7 +35,8 @@
 // Disable auto-formatting for this large table
 // clang-format off
 
-// Set up data structure with number of bytes and number of channels for each Vulkan format
+// Set up data structure with size(bytes) and number of channels for each Vulkan format
+// For compressed and multi-plane formats, size is bytes per compressed or shared block
 const std::map<VkFormat, VULKAN_FORMAT_INFO> vk_format_table = {
     {VK_FORMAT_UNDEFINED,                   {0, 0, VK_FORMAT_COMPATIBILITY_CLASS_NONE_BIT }},
     {VK_FORMAT_R4G4_UNORM_PACK8,            {1, 2, VK_FORMAT_COMPATIBILITY_CLASS_8_BIT}},
@@ -230,43 +231,48 @@
     {VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,  {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC1_4BPP_BIT}},
     {VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,  {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_2BPP_BIT}},
     {VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,  {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_PVRTC2_4BPP_BIT}},
-    /* KHR_sampler_YCbCr_conversion */
-    {VK_FORMAT_G8B8G8R8_422_UNORM_KHR,                          {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_G8B8G8R8}},
-    {VK_FORMAT_B8G8R8G8_422_UNORM_KHR,                          {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_B8G8R8G8}},
-    {VK_FORMAT_R10X6_UNORM_PACK16_KHR,                          {2, 1, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
-    {VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR,                    {4, 2, VK_FORMAT_COMPATIBILITY_CLASS_32_BIT}},
-    {VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR,          {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R10G10B10A10}},
-    {VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G10B10G10R10}},
-    {VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B10G10R10G10}},
-    {VK_FORMAT_R12X4_UNORM_PACK16,                              {2, 1, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
-    {VK_FORMAT_R12X4G12X4_UNORM_2PACK16,                        {4, 2, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
-    {VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR,          {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R12G12B12A12}},
-    {VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G12B12G12R12}},
-    {VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B12G12R12G12}},
-    {VK_FORMAT_G16B16G16R16_422_UNORM_KHR,                      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G16B16G16R16}},
-    {VK_FORMAT_B16G16R16G16_422_UNORM_KHR,                      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B16G16R16G16}}
-#if 0   // TBD - Figure out what 'size' means for multi-planar formats
-    {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR,                   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_420}},
-    {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR,                    {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_420}},
-    {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR,                   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_422}},
-    {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR,                    {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_422}},
-    {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR,                   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_444}},
-    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_420}},
-    {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR,   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_420}},
-    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_422}},
-    {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR,   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_422}},
-    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_444}},
-    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_420}},
-    {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR,   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_420}},
-    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_422}},
-    {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR,   {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_422}},
-    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR,  {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_444}},
-    {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR,                {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_420}},
-    {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR,                 {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_420}},
-    {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR,                {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_422}},
-    {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR,                 {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_422}},
-    {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR,                {0, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_444}}
-#endif
+    // KHR_sampler_YCbCr_conversion extension - single-plane variants
+    // 'PACK' formats are normal, uncompressed
+    {VK_FORMAT_R10X6_UNORM_PACK16,                          {2, 1, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
+    {VK_FORMAT_R10X6G10X6_UNORM_2PACK16,                    {4, 2, VK_FORMAT_COMPATIBILITY_CLASS_32_BIT}},
+    {VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,          {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R10G10B10A10}},
+    {VK_FORMAT_R12X4_UNORM_PACK16,                          {2, 1, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
+    {VK_FORMAT_R12X4G12X4_UNORM_2PACK16,                    {4, 2, VK_FORMAT_COMPATIBILITY_CLASS_16_BIT}},
+    {VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,          {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_R12G12B12A12}},
+    // _422 formats encode 2 texels per entry with B, R components shared - treated as compressed w/ 2x1 block size
+    {VK_FORMAT_G8B8G8R8_422_UNORM,                          {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_G8B8G8R8}},
+    {VK_FORMAT_B8G8R8G8_422_UNORM,                          {4, 4, VK_FORMAT_COMPATIBILITY_CLASS_32BIT_B8G8R8G8}},
+    {VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G10B10G10R10}},
+    {VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B10G10R10G10}},
+    {VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G12B12G12R12}},
+    {VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B12G12R12G12}},
+    {VK_FORMAT_G16B16G16R16_422_UNORM,                      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_G16B16G16R16}},
+    {VK_FORMAT_B16G16R16G16_422_UNORM,                      {8, 4, VK_FORMAT_COMPATIBILITY_CLASS_64BIT_B16G16R16G16}},
+    // KHR_sampler_YCbCr_conversion extension - multi-plane variants
+    // Formats that 'share' components among texels (_420 and _422), size represents total bytes for the smallest possible texel block
+    // _420 share B, R components within a 2x2 texel block
+    {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,                   {6, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_420}},
+    {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,                    {6, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_420}},
+    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,  {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_420}},
+    {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,   {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_420}},
+    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,  {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_420}},
+    {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,   {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_420}},
+    {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,                {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_420}},
+    {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,                 {12, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_420}},
+    // _422 share B, R components within a 2x1 texel block
+    {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,                   {4, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_422}},
+    {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,                    {4, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_2PLANE_422}},
+    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,  {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_422}},
+    {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,   {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_2PLANE_422}},
+    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,  {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_422}},
+    {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,   {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_2PLANE_422}},
+    {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,                {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_422}},
+    {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,                 {8, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_2PLANE_422}},
+    // _444 do not share
+    {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,                   {3, 3, VK_FORMAT_COMPATIBILITY_CLASS_8BIT_3PLANE_444}},
+    {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,  {6, 3, VK_FORMAT_COMPATIBILITY_CLASS_10BIT_3PLANE_444}},
+    {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,  {6, 3, VK_FORMAT_COMPATIBILITY_CLASS_12BIT_3PLANE_444}},
+    {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,                {6, 3, VK_FORMAT_COMPATIBILITY_CLASS_16BIT_3PLANE_444}}
 };
 
 // Renable formatting
@@ -447,6 +453,26 @@
         case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
         case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
         case VK_FORMAT_X8_D24_UNORM_PACK32:
+        case VK_FORMAT_R10X6_UNORM_PACK16:
+        case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
+        case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+        case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+        case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+        case VK_FORMAT_R12X4_UNORM_PACK16:
+        case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
+        case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+        case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+        case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
             found = true;
             break;
         default:
@@ -455,6 +481,15 @@
     return found;
 }
 
+// Return true if format is 'normal', with one texel per format element
+VK_LAYER_EXPORT bool FormatElementIsTexel(VkFormat format) {
+    if (FormatIsPacked(format) || FormatIsCompressed(format) || FormatIsSinglePlane_422(format) || FormatIsMultiplane(format)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
 // Return true if format is a depth or stencil format
 VK_LAYER_EXPORT bool FormatIsDepthOrStencil(VkFormat format) {
     return (FormatIsDepthAndStencil(format) || FormatIsDepthOnly(format) || FormatIsStencilOnly(format));
@@ -860,8 +895,11 @@
     return is_sscaled;
 }
 
-// Return compressed texel block sizes for block compressed formats
-VK_LAYER_EXPORT VkExtent3D FormatCompressedTexelBlockExtent(VkFormat format) {
+// Return texel block sizes for all formats
+// Uncompressed formats return {1, 1, 1}
+// Compressed formats return the compression block extents
+// Multiplane formats return the 'shared' extent of their low-res channel(s)
+VK_LAYER_EXPORT VkExtent3D FormatTexelBlockExtent(VkFormat format) {
     VkExtent3D block_size = {1, 1, 1};
     switch (format) {
         case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
@@ -958,48 +996,148 @@
         case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
             block_size = {4, 4, 1};
             break;
-        // With KHR_sampler_ycbcr_conversion, these formats are treated as 2x1 compressed (for copies)
-        case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
-        case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
-        case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
-        case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
-        case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
-        case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
-        case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
-        case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
+        // (KHR_sampler_ycbcr_conversion) _422 single-plane formats are treated as 2x1 compressed (for copies)
+        case VK_FORMAT_G8B8G8R8_422_UNORM:
+        case VK_FORMAT_B8G8R8G8_422_UNORM:
+        case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+        case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+        case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+        case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+        case VK_FORMAT_G16B16G16R16_422_UNORM:
+        case VK_FORMAT_B16G16R16G16_422_UNORM:
             block_size = {2, 1, 1};
             break;
-
+        // _422 multi-plane formats are not considered compressed, but shared components form a logical 2x1 block
+        case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+        case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+        case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+            block_size = {2, 1, 1};
+            break;
+        // _420 formats are not considered compressed, but shared components form a logical 2x2 block
+        case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+        case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+        case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+            block_size = {2, 2, 1};
+            break;
+        // _444 multi-plane formats do not share components, default to 1x1
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+        case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+        case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
         default:
             break;
     }
     return block_size;
 }
 
+VK_LAYER_EXPORT uint32_t FormatDepthSize(VkFormat format) {
+    uint32_t depth_size = 0;
+    switch (format) {
+        case VK_FORMAT_D16_UNORM:
+        case VK_FORMAT_D16_UNORM_S8_UINT:
+            depth_size = 16;
+            break;
+        case VK_FORMAT_X8_D24_UNORM_PACK32:
+        case VK_FORMAT_D24_UNORM_S8_UINT:
+            depth_size = 24;
+            break;
+        case VK_FORMAT_D32_SFLOAT:
+        case VK_FORMAT_D32_SFLOAT_S8_UINT:
+            depth_size = 32;
+            break;
+
+        default:
+            break;
+    }
+    return depth_size;
+}
+
+VK_LAYER_EXPORT VkFormatNumericalType FormatDepthNumericalType(VkFormat format) {
+    VkFormatNumericalType numerical_type = VK_FORMAT_NUMERICAL_TYPE_NONE;
+    switch (format) {
+        case VK_FORMAT_D16_UNORM:
+        case VK_FORMAT_D16_UNORM_S8_UINT:
+        case VK_FORMAT_X8_D24_UNORM_PACK32:
+        case VK_FORMAT_D24_UNORM_S8_UINT:
+            numerical_type = VK_FORMAT_NUMERICAL_TYPE_UNORM;
+            break;
+        case VK_FORMAT_D32_SFLOAT:
+        case VK_FORMAT_D32_SFLOAT_S8_UINT:
+            numerical_type = VK_FORMAT_NUMERICAL_TYPE_SFLOAT;
+            break;
+
+        default:
+            break;
+    }
+    return numerical_type;
+}
+
+VK_LAYER_EXPORT uint32_t FormatStencilSize(VkFormat format) {
+    uint32_t stencil_size = 0;
+    switch (format) {
+        case VK_FORMAT_S8_UINT:
+        case VK_FORMAT_D16_UNORM_S8_UINT:
+        case VK_FORMAT_D24_UNORM_S8_UINT:
+        case VK_FORMAT_D32_SFLOAT_S8_UINT:
+            stencil_size = 8;
+            break;
+
+        default:
+            break;
+    }
+    return stencil_size;
+}
+
+VK_LAYER_EXPORT VkFormatNumericalType FormatStencilNumericalType(VkFormat format) {
+    VkFormatNumericalType numerical_type = VK_FORMAT_NUMERICAL_TYPE_NONE;
+    switch (format) {
+        case VK_FORMAT_S8_UINT:
+        case VK_FORMAT_D16_UNORM_S8_UINT:
+        case VK_FORMAT_D24_UNORM_S8_UINT:
+        case VK_FORMAT_D32_SFLOAT_S8_UINT:
+            numerical_type = VK_FORMAT_NUMERICAL_TYPE_UINT;
+            break;
+
+        default:
+            break;
+    }
+    return numerical_type;
+}
+
 VK_LAYER_EXPORT uint32_t FormatPlaneCount(VkFormat format) {
     switch (format) {
-        case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
-        case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
-        case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
-        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
-        case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
-        case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+        case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+        case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+        case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+        case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+        case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+        case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
             return 3;
             break;
-        case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
-        case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
-        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
-        case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
-        case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
+        case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+        case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+        case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+        case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+        case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
             return 2;
             break;
         default:
@@ -1017,8 +1155,9 @@
     return VK_FORMAT_COMPATIBILITY_CLASS_NONE_BIT;
 }
 
-// Return size, in bytes, of a pixel of the specified format
-VK_LAYER_EXPORT size_t FormatSize(VkFormat format) {
+// Return size, in bytes, of one element of the specified format
+// For uncompressed this is one texel, for compressed it is one block
+VK_LAYER_EXPORT uint32_t FormatElementSize(VkFormat format) {
     auto item = vk_format_table.find(format);
     if (item != vk_format_table.end()) {
         return item->second.size;
@@ -1026,6 +1165,18 @@
     return 0;
 }
 
+// Return the size in bytes of one texel of given foramt
+// For compressed or multi-plane, this may be a fractional number
+VK_LAYER_EXPORT double FormatTexelSize(VkFormat format) {
+    double texel_size = static_cast<double>(FormatElementSize(format));
+    VkExtent3D block_extent = FormatTexelBlockExtent(format);
+    uint32_t texels_per_block = block_extent.width * block_extent.height * block_extent.depth;
+    if (1 < texels_per_block) {
+        texel_size /= static_cast<double>(texels_per_block);
+    }
+    return texel_size;
+}
+
 // Return the number of channels for a given format
 uint32_t FormatChannelCount(VkFormat format) {
     auto item = vk_format_table.find(format);
@@ -1057,88 +1208,70 @@
 // Source: Vulkan spec Table 45. Plane Format Compatibility Table
 // clang-format off
 const std::map<VkFormat, VULKAN_MULTIPLANE_COMPATIBILITY> vk_multiplane_compatibility_map {
-    { VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R8_UNORM } } } },
-    { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR,                   { { { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R8G8_UNORM },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R8_UNORM } } } },
-    { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR,                   { { { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R8G8_UNORM },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 1, 1, VK_FORMAT_R8_UNORM },
-                                                                    { 1, 1, VK_FORMAT_R8_UNORM } } } },
-    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR,  { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR,  { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR,  { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 2, VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR,  { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 2, 1, VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR },
-                                                                    { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16_KHR } } } },
-    { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR,               { { { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R16_UNORM } } } },
-    { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR,                { { { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 2, VK_FORMAT_R16G16_UNORM },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR,               { { { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R16_UNORM } } } },
-    { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR,                { { { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 2, 1, VK_FORMAT_R16G16_UNORM },
-                                                                    { 1, 1, VK_FORMAT_UNDEFINED } } } },
-    { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR,               { { { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 1, 1, VK_FORMAT_R16_UNORM },
-                                                                    { 1, 1, VK_FORMAT_R16_UNORM } } } }
+    { VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 2, 2, VK_FORMAT_R8_UNORM },
+                                                                { 2, 2, VK_FORMAT_R8_UNORM } } } },
+    { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,                   { { { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 2, 2, VK_FORMAT_R8G8_UNORM },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 2, 1, VK_FORMAT_R8_UNORM },
+                                                                { 2, 1, VK_FORMAT_R8_UNORM } } } },
+    { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,                   { { { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 2, 1, VK_FORMAT_R8G8_UNORM },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,                  { { { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 1, 1, VK_FORMAT_R8_UNORM },
+                                                                { 1, 1, VK_FORMAT_R8_UNORM } } } },
+    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R10X6_UNORM_PACK16 } } } },
+    { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,  { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R10X6G10X6_UNORM_2PACK16 },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R10X6_UNORM_PACK16 } } } },
+    { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,  { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R10X6G10X6_UNORM_2PACK16 },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 },
+                                                                { 1, 1, VK_FORMAT_R10X6_UNORM_PACK16 } } } },
+    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R12X4_UNORM_PACK16 } } } },
+    { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,  { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 2, VK_FORMAT_R12X4G12X4_UNORM_2PACK16 },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R12X4_UNORM_PACK16 } } } },
+    { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,  { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 2, 1, VK_FORMAT_R12X4G12X4_UNORM_2PACK16 },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, { { { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 },
+                                                                { 1, 1, VK_FORMAT_R12X4_UNORM_PACK16 } } } },
+    { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,               { { { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 2, 2, VK_FORMAT_R16_UNORM },
+                                                                { 2, 2, VK_FORMAT_R16_UNORM } } } },
+    { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,                { { { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 2, 2, VK_FORMAT_R16G16_UNORM },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,               { { { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 2, 1, VK_FORMAT_R16_UNORM },
+                                                                { 2, 1, VK_FORMAT_R16_UNORM } } } },
+    { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,                { { { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 2, 1, VK_FORMAT_R16G16_UNORM },
+                                                                { 1, 1, VK_FORMAT_UNDEFINED } } } },
+    { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,               { { { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 1, 1, VK_FORMAT_R16_UNORM },
+                                                                { 1, 1, VK_FORMAT_R16_UNORM } } } }
 };
 // clang-format on
 
-VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat mp_fmt, uint32_t plane) {
-    auto it = vk_multiplane_compatibility_map.find(mp_fmt);
-    if ((it == vk_multiplane_compatibility_map.end()) || (plane >= VK_MULTIPLANE_FORMAT_MAX_PLANES)) {
-        return VK_FORMAT_UNDEFINED;
-    }
-
-    return it->second.per_plane[plane].compatible_format;
-}
-
-// Return alignment, in bytes, of a data for the specified format
-VK_LAYER_EXPORT size_t FormatAlignment(VkFormat format) {
-    if (FormatIsPacked(format)) {
-        return FormatSize(format);
-    } else {
-        return FormatSize(format) / FormatChannelCount(format);
-    }
-}
-
-uint32_t GetPlaneSizeIndex(VkImageAspectFlags aspect) {
+uint32_t GetPlaneIndex(VkImageAspectFlags aspect) {
     switch (aspect) {
         case VK_IMAGE_ASPECT_PLANE_0_BIT:
             return 0;
@@ -1155,6 +1288,29 @@
     }
 }
 
+VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat mp_fmt, VkImageAspectFlags plane_aspect) {
+    uint32_t plane_idx = GetPlaneIndex(plane_aspect);
+    auto it = vk_multiplane_compatibility_map.find(mp_fmt);
+    if ((it == vk_multiplane_compatibility_map.end()) || (plane_idx >= VK_MULTIPLANE_FORMAT_MAX_PLANES)) {
+        return VK_FORMAT_UNDEFINED;
+    }
+
+    return it->second.per_plane[plane_idx].compatible_format;
+}
+
+VK_LAYER_EXPORT VkExtent2D FindMultiplaneExtentDivisors(VkFormat mp_fmt, VkImageAspectFlags plane_aspect) {
+    VkExtent2D divisors = {1, 1};
+    uint32_t plane_idx = GetPlaneIndex(plane_aspect);
+    auto it = vk_multiplane_compatibility_map.find(mp_fmt);
+    if ((it == vk_multiplane_compatibility_map.end()) || (plane_idx >= VK_MULTIPLANE_FORMAT_MAX_PLANES)) {
+        return divisors;
+    }
+
+    divisors.width = it->second.per_plane[plane_idx].width_divisor;
+    divisors.height = it->second.per_plane[plane_idx].height_divisor;
+    return divisors;
+}
+
 VK_LAYER_EXPORT bool FormatSizesAreEqual(VkFormat srcFormat, VkFormat dstFormat, uint32_t region_count,
                                          const VkImageCopy *regions) {
     size_t srcSize = 0, dstSize = 0;
@@ -1162,25 +1318,23 @@
     if (FormatIsMultiplane(srcFormat) || FormatIsMultiplane(dstFormat)) {
         for (uint32_t i = 0; i < region_count; i++) {
             if (FormatIsMultiplane(srcFormat)) {
-                VkFormat planeFormat =
-                    FindMultiplaneCompatibleFormat(srcFormat, GetPlaneSizeIndex(regions[i].srcSubresource.aspectMask));
-                srcSize = FormatSize(planeFormat);
+                VkFormat planeFormat = FindMultiplaneCompatibleFormat(srcFormat, regions[i].srcSubresource.aspectMask);
+                srcSize = FormatElementSize(planeFormat);
             } else {
-                srcSize = FormatSize(srcFormat);
+                srcSize = FormatElementSize(srcFormat);
             }
             if (FormatIsMultiplane(dstFormat)) {
-                VkFormat planeFormat =
-                    FindMultiplaneCompatibleFormat(dstFormat, GetPlaneSizeIndex(regions[i].dstSubresource.aspectMask));
-                dstSize = FormatSize(planeFormat);
+                VkFormat planeFormat = FindMultiplaneCompatibleFormat(dstFormat, regions[i].dstSubresource.aspectMask);
+                dstSize = FormatElementSize(planeFormat);
             } else {
-                dstSize = FormatSize(dstFormat);
+                dstSize = FormatElementSize(dstFormat);
             }
             if (dstSize != srcSize) return false;
         }
         return true;
     } else {
-        srcSize = FormatSize(srcFormat);
-        dstSize = FormatSize(dstFormat);
+        srcSize = FormatElementSize(srcFormat);
+        dstSize = FormatElementSize(dstFormat);
         return (dstSize == srcSize);
     }
 }
diff --git a/layers/vk_format_utils.h b/layers/vk_format_utils.h
index 72c745e..96cc3cf 100644
--- a/layers/vk_format_utils.h
+++ b/layers/vk_format_utils.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2015-2017 The Khronos Group Inc.
- * Copyright (c) 2015-2017 Valve Corporation
- * Copyright (c) 2015-2017 LunarG, Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -124,6 +124,19 @@
     VK_FORMAT_COMPATIBILITY_CLASS_MAX_ENUM = 79
 } VkFormatCompatibilityClass;
 
+typedef enum VkFormatNumericalType {
+    VK_FORMAT_NUMERICAL_TYPE_NONE,
+    VK_FORMAT_NUMERICAL_TYPE_UINT,
+    VK_FORMAT_NUMERICAL_TYPE_SINT,
+    VK_FORMAT_NUMERICAL_TYPE_UNORM,
+    VK_FORMAT_NUMERICAL_TYPE_SNORM,
+    VK_FORMAT_NUMERICAL_TYPE_USCALED,
+    VK_FORMAT_NUMERICAL_TYPE_SSCALED,
+    VK_FORMAT_NUMERICAL_TYPE_UFLOAT,
+    VK_FORMAT_NUMERICAL_TYPE_SFLOAT,
+    VK_FORMAT_NUMERICAL_TYPE_SRGB
+} VkFormatNumericalType;
+
 VK_LAYER_EXPORT bool FormatIsDepthOrStencil(VkFormat format);
 VK_LAYER_EXPORT bool FormatIsDepthAndStencil(VkFormat format);
 VK_LAYER_EXPORT bool FormatIsDepthOnly(VkFormat format);
@@ -145,16 +158,22 @@
 VK_LAYER_EXPORT bool FormatIsSScaled(VkFormat format);
 VK_LAYER_EXPORT bool FormatIsCompressed(VkFormat format);
 VK_LAYER_EXPORT bool FormatIsPacked(VkFormat format);
+VK_LAYER_EXPORT bool FormatElementIsTexel(VkFormat format);
 VK_LAYER_EXPORT bool FormatSizesAreEqual(VkFormat srcFormat, VkFormat dstFormat, uint32_t region_count, const VkImageCopy *regions);
 
+VK_LAYER_EXPORT uint32_t FormatDepthSize(VkFormat format);
+VK_LAYER_EXPORT VkFormatNumericalType FormatDepthNumericalType(VkFormat format);
+VK_LAYER_EXPORT uint32_t FormatStencilSize(VkFormat format);
+VK_LAYER_EXPORT VkFormatNumericalType FormatStencilNumericalType(VkFormat format);
 VK_LAYER_EXPORT uint32_t FormatPlaneCount(VkFormat format);
 VK_LAYER_EXPORT uint32_t FormatChannelCount(VkFormat format);
-VK_LAYER_EXPORT VkExtent3D FormatCompressedTexelBlockExtent(VkFormat format);
-VK_LAYER_EXPORT size_t FormatSize(VkFormat format);
+VK_LAYER_EXPORT VkExtent3D FormatTexelBlockExtent(VkFormat format);
+VK_LAYER_EXPORT uint32_t FormatElementSize(VkFormat format);
+VK_LAYER_EXPORT double FormatTexelSize(VkFormat format);
 VK_LAYER_EXPORT VkFormatCompatibilityClass FormatCompatibilityClass(VkFormat format);
 VK_LAYER_EXPORT VkDeviceSize SafeModulo(VkDeviceSize dividend, VkDeviceSize divisor);
-VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat fmt, uint32_t plane);
-VK_LAYER_EXPORT size_t FormatAlignment(VkFormat format);
+VK_LAYER_EXPORT VkFormat FindMultiplaneCompatibleFormat(VkFormat fmt, VkImageAspectFlags plane_aspect);
+VK_LAYER_EXPORT VkExtent2D FindMultiplaneExtentDivisors(VkFormat mp_fmt, VkImageAspectFlags plane_aspect);
 
 static inline bool FormatIsUndef(VkFormat format) { return (format == VK_FORMAT_UNDEFINED); }
 static inline bool FormatHasDepth(VkFormat format) { return (FormatIsDepthOnly(format) || FormatIsDepthAndStencil(format)); }
diff --git a/layers/vk_layer_config.cpp b/layers/vk_layer_config.cpp
index 5671039..8967916 100644
--- a/layers/vk_layer_config.cpp
+++ b/layers/vk_layer_config.cpp
@@ -202,7 +202,7 @@
 #if defined(WIN32)
     HKEY hive;
     LSTATUS err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Khronos\\Vulkan\\Settings", 0, KEY_READ, &hive);
-    if (err != ERROR_SUCCESS) {
+    if (err == ERROR_SUCCESS) {
         char name[2048];
         DWORD i = 0, name_size = sizeof(name), type, value, value_size = sizeof(value);
         while (ERROR_SUCCESS ==
@@ -213,7 +213,7 @@
             }
 
             // Check if this actually points to a file
-            if ((stat(name, &info) != 0) || (info.st_mode & S_IFREG)) {
+            if ((stat(name, &info) != 0) || !(info.st_mode & S_IFREG)) {
                 continue;
             }
 
diff --git a/layers/vk_layer_logging.h b/layers/vk_layer_logging.h
index ad02bb6..68b6ee1 100644
--- a/layers/vk_layer_logging.h
+++ b/layers/vk_layer_logging.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 #include "vk_object_types.h"
 #include "vk_validation_error_messages.h"
 #include "vk_layer_dispatch_table.h"
+#include <mutex>
 #include <signal.h>
 #include <cinttypes>
 #include <stdarg.h>
@@ -49,6 +50,17 @@
 #define DECORATE_UNUSED
 #endif
 
+#if defined __ANDROID__
+#include <android/log.h>
+#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
+#else
+#define LOGCONSOLE(...)      \
+    {                        \
+        printf(__VA_ARGS__); \
+        printf("\n");        \
+    }
+#endif
+
 static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
 
 #undef DECORATE_UNUSED
@@ -68,18 +80,80 @@
 } LoggingLabelData;
 
 typedef struct _debug_report_data {
-    VkLayerDbgFunctionNode *debug_callback_list;
-    VkLayerDbgFunctionNode *default_debug_callback_list;
-    VkDebugUtilsMessageSeverityFlagsEXT active_severities;
-    VkDebugUtilsMessageTypeFlagsEXT active_types;
-    bool g_DEBUG_REPORT;
-    bool g_DEBUG_UTILS;
-    std::unordered_map<uint64_t, std::string> *debugObjectNameMap;
-    std::unordered_map<uint64_t, std::string> *debugUtilsObjectNameMap;
-    std::unordered_map<VkQueue, std::vector<LoggingLabelData>> *debugUtilsQueueLabels;
-    bool queueLabelHasInsert;
-    std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> *debugUtilsCmdBufLabels;
-    bool cmdBufLabelHasInsert;
+    VkLayerDbgFunctionNode *debug_callback_list{nullptr};
+    VkLayerDbgFunctionNode *default_debug_callback_list{nullptr};
+    VkDebugUtilsMessageSeverityFlagsEXT active_severities{0};
+    VkDebugUtilsMessageTypeFlagsEXT active_types{0};
+    bool g_DEBUG_REPORT{false};
+    bool g_DEBUG_UTILS{false};
+    bool queueLabelHasInsert{false};
+    bool cmdBufLabelHasInsert{false};
+    std::unordered_map<uint64_t, std::string> debugObjectNameMap;
+    std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap;
+    std::unordered_map<VkQueue, std::vector<LoggingLabelData>> debugUtilsQueueLabels;
+    std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> debugUtilsCmdBufLabels;
+    // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows
+    // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes.
+    mutable std::mutex debug_report_mutex;
+
+    void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
+        std::unique_lock<std::mutex> lock(debug_report_mutex);
+        if (pNameInfo->pObjectName) {
+            debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName;
+        } else {
+            debugUtilsObjectNameMap.erase(pNameInfo->objectHandle);
+        }
+    }
+
+    void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
+        std::unique_lock<std::mutex> lock(debug_report_mutex);
+        if (pNameInfo->pObjectName) {
+            debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName;
+        } else {
+            debugObjectNameMap.erase(pNameInfo->object);
+        }
+    }
+
+    std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
+        std::string label = "";
+        const auto utils_name_iter = debugUtilsObjectNameMap.find(object);
+        if (utils_name_iter != debugUtilsObjectNameMap.end()) {
+            label = utils_name_iter->second;
+        }
+        return label;
+    }
+
+    std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
+        std::string label = "";
+        const auto marker_name_iter = debugObjectNameMap.find(object);
+        if (marker_name_iter != debugObjectNameMap.end()) {
+            label = marker_name_iter->second;
+        }
+        return label;
+    }
+
+    template <typename HANDLE_T>
+    std::string FormatHandle(HANDLE_T *h) const {
+        return FormatHandle(HandleToUint64(h));
+    }
+
+    std::string FormatHandle(uint64_t h) const {
+        char uint64_string[64];
+        sprintf(uint64_string, "0x%" PRIxLEAST64, h);
+        std::string ret = uint64_string;
+
+        std::string name = DebugReportGetUtilsObjectName(h);
+        if (name.empty()) {
+            name = DebugReportGetMarkerObjectName(h);
+        }
+        if (!name.empty()) {
+            ret.append("[");
+            ret.append(name);
+            ret.append("]");
+        }
+        return ret;
+    }
+
 } debug_report_data;
 
 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
@@ -303,8 +377,8 @@
         oss << "Object: 0x" << std::hex << src_object;
         // If this is a queue, add any queue labels to the callback data.
         if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
-            auto label_iter = debug_data->debugUtilsQueueLabels->find(reinterpret_cast<VkQueue>(src_object));
-            if (label_iter != debug_data->debugUtilsQueueLabels->end()) {
+            auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
+            if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
                 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
                 if (nullptr != queue_labels) {
                     // Record the labels, but record them in reverse order since we want the
@@ -326,8 +400,8 @@
             }
             // If this is a command buffer, add any command buffer labels to the callback data.
         } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
-            auto label_iter = debug_data->debugUtilsCmdBufLabels->find(reinterpret_cast<VkCommandBuffer>(src_object));
-            if (label_iter != debug_data->debugUtilsCmdBufLabels->end()) {
+            auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
+            if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
                 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
                 if (nullptr != cmd_buf_labels) {
                     // Record the labels, but record them in reverse order since we want the
@@ -348,19 +422,15 @@
                 }
             }
         }
+
         // Look for any debug utils or marker names to use for this object
-        callback_data.pObjects[0].pObjectName = NULL;
-        auto utils_name_iter = debug_data->debugUtilsObjectNameMap->find(src_object);
-        if (utils_name_iter != debug_data->debugUtilsObjectNameMap->end()) {
-            callback_data.pObjects[0].pObjectName = utils_name_iter->second.c_str();
-        } else {
-            auto marker_name_iter = debug_data->debugObjectNameMap->find(src_object);
-            if (marker_name_iter != debug_data->debugObjectNameMap->end()) {
-                callback_data.pObjects[0].pObjectName = marker_name_iter->second.c_str();
-            }
+        std::string label = debug_data->DebugReportGetUtilsObjectName(src_object);
+        if (label.empty()) {
+            label = debug_data->DebugReportGetMarkerObjectName(src_object);
         }
-        if (NULL != callback_data.pObjects[0].pObjectName) {
-            oss << " (Name = " << callback_data.pObjects[0].pObjectName << " : Type = ";
+        if (!label.empty()) {
+            object_name_info.pObjectName = label.c_str();
+            oss << " (Name = " << label << " : Type = ";
         } else {
             oss << " (Type = ";
         }
@@ -429,7 +499,8 @@
 static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
                                            VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
                                            VkDebugUtilsMessageTypeFlagsEXT message_type,
-                                           VkDebugUtilsMessengerCallbackDataEXT *callback_data) {
+                                           VkDebugUtilsMessengerCallbackDataEXT *callback_data,
+                                           const VkDebugUtilsMessengerEXT *messenger) {
     bool bail = false;
     VkLayerDbgFunctionNode *layer_dbg_node = NULL;
 
@@ -443,33 +514,37 @@
 
     DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
 
+    VkDebugUtilsObjectNameInfoEXT object_name_info;
+    object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    object_name_info.pNext = NULL;
+    object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
+    object_name_info.objectHandle = HandleToUint64(*messenger);
+    object_name_info.pObjectName = NULL;
+    callback_data->pObjects = &object_name_info;
+    callback_data->objectCount = 1;
+
     while (layer_dbg_node) {
         if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
             (layer_dbg_node->messenger.messageType & message_type)) {
-            // Loop through each object and give it the proper name if it was set.
-            for (uint32_t obj = 0; obj < callback_data->objectCount; obj++) {
-                auto it = debug_data->debugUtilsObjectNameMap->find(callback_data->pObjects[obj].objectHandle);
-                if (it == debug_data->debugUtilsObjectNameMap->end()) {
-                    continue;
-                }
-                callback_data->pObjects[obj].pObjectName = it->second.c_str();
+            std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
+            if (!messenger_label.empty()) {
+                object_name_info.pObjectName = messenger_label.c_str();
             }
             if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
                                                           layer_dbg_node->pUserData)) {
                 bail = true;
             }
         } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
-            auto it = debug_data->debugObjectNameMap->find(callback_data->pObjects[0].objectHandle);
             VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
-            if (it == debug_data->debugObjectNameMap->end()) {
+            std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
+            if (marker_label.empty()) {
                 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
                                                           callback_data->messageIdNumber, callback_data->pMessageIdName,
                                                           callback_data->pMessage, layer_dbg_node->pUserData)) {
                     bail = true;
                 }
             } else {
-                std::string newMsg = "SrcObject name = ";
-                newMsg.append(it->second.c_str());
+                std::string newMsg = "SrcObject name = " + marker_label;
                 newMsg.append(" ");
                 newMsg.append(callback_data->pMessage);
                 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
@@ -489,36 +564,24 @@
     VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
     const char *const *enabled_extensions)  // layer or extension name to be enabled
 {
-    debug_report_data *debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
-    if (!debug_data) return NULL;
-
-    memset(debug_data, 0, sizeof(debug_report_data));
+    debug_report_data *debug_data = new debug_report_data;
     for (uint32_t i = 0; i < extension_count; i++) {
-        // TODO: Check other property fields
         if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
             debug_data->g_DEBUG_REPORT = true;
         } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
             debug_data->g_DEBUG_UTILS = true;
         }
     }
-    debug_data->debugObjectNameMap = new std::unordered_map<uint64_t, std::string>;
-    debug_data->debugUtilsObjectNameMap = new std::unordered_map<uint64_t, std::string>;
-    debug_data->debugUtilsQueueLabels = new std::unordered_map<VkQueue, std::vector<LoggingLabelData>>;
-    debug_data->debugUtilsCmdBufLabels = new std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>>;
-    debug_data->queueLabelHasInsert = false;
-    debug_data->cmdBufLabelHasInsert = false;
     return debug_data;
 }
 
 static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
     if (debug_data) {
+        std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
         RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
         RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
-        delete debug_data->debugObjectNameMap;
-        delete debug_data->debugUtilsObjectNameMap;
-        delete debug_data->debugUtilsQueueLabels;
-        delete debug_data->debugUtilsCmdBufLabels;
-        free(debug_data);
+        lock.unlock();
+        delete (debug_data);
     }
 }
 
@@ -534,6 +597,7 @@
 
 static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
                                                     const VkAllocationCallbacks *allocator) {
+    std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
     RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
     RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
 }
@@ -542,6 +606,7 @@
                                                        const VkDebugUtilsMessengerCreateInfoEXT *create_info,
                                                        const VkAllocationCallbacks *allocator,
                                                        VkDebugUtilsMessengerEXT *messenger) {
+    std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
     if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
@@ -564,7 +629,6 @@
     }
 
     VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
-    VkDebugUtilsObjectNameInfoEXT blank_object = {};
     callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
     callback_data.pNext = NULL;
     callback_data.flags = 0;
@@ -575,20 +639,16 @@
     callback_data.pQueueLabels = NULL;
     callback_data.cmdBufLabelCount = 0;
     callback_data.pCmdBufLabels = NULL;
-    callback_data.objectCount = 1;
-    callback_data.pObjects = &blank_object;
-    blank_object.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
-    blank_object.pNext = NULL;
-    blank_object.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
-    blank_object.objectHandle = HandleToUint64(*messenger);
-    blank_object.pObjectName = NULL;
+    callback_data.objectCount = 0;
+    callback_data.pObjects = NULL;
     debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
-                            VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data);
+                            VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
     return VK_SUCCESS;
 }
 
 static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
                                                  const VkAllocationCallbacks *allocator) {
+    std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
     RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
     RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
 }
@@ -596,6 +656,7 @@
 static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
                                                     const VkDebugReportCallbackCreateInfoEXT *create_info,
                                                     const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
+    std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
     if (!pNewDbgFuncNode) {
         return VK_ERROR_OUT_OF_HOST_MEMORY;
@@ -846,11 +907,13 @@
     va_start(argptr, fmt);
     int reserve = vsnprintf(nullptr, 0, fmt, argptr);
     va_end(argptr);
-    formatted.reserve(reserve + 1);
+    formatted.reserve(reserve + 1);  // Set the storage length long enough to hold the output + null
+    formatted.resize(reserve);       // Set the *logical* length to be what vsprintf will write
     va_start(argptr, fmt);
     int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
     va_end(argptr);
     assert(result == reserve);
+    assert((formatted.size() == strlen(formatted.c_str())));
     return result;
 }
 
@@ -878,6 +941,8 @@
 #endif
 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
                            uint64_t src_object, std::string vuid_text, const char *format, ...) {
+    if (!debug_data) return false;
+    std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
     VkFlags local_severity = 0;
     VkFlags local_type = 0;
     DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
@@ -931,13 +996,22 @@
 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
                                                                  uint64_t src_object, size_t location, int32_t msg_code,
                                                                  const char *layer_prefix, const char *message, void *user_data) {
+    std::ostringstream msg_buffer;
     char msg_flag_string[30];
 
     PrintMessageFlags(msg_flags, msg_flag_string);
 
-    fprintf((FILE *)user_data, "%s(%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
+    msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
+    const std::string tmp = msg_buffer.str();
+    const char *cstr = tmp.c_str();
+
+    fprintf((FILE *)user_data, "%s", cstr);
     fflush((FILE *)user_data);
 
+#if defined __ANDROID__
+    LOGCONSOLE("%s", cstr);
+#endif
+
     return false;
 }
 
@@ -974,22 +1048,32 @@
                                                                     VkDebugUtilsMessageTypeFlagsEXT message_type,
                                                                     const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
                                                                     void *user_data) {
+    std::ostringstream msg_buffer;
     char msg_severity[30];
     char msg_type[30];
 
     PrintMessageSeverity(message_severity, msg_severity);
     PrintMessageType(message_type, msg_type);
 
-    fprintf((FILE *)user_data, "%s(%s / %s): msgNum: %d - %s\n", callback_data->pMessageIdName, msg_severity, msg_type,
-            callback_data->messageIdNumber, callback_data->pMessage);
-    fprintf((FILE *)user_data, "    Objects: %d\n", callback_data->objectCount);
+    msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
+               << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
+    msg_buffer << "    Objects: " << callback_data->objectCount << "\n";
     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
-        fprintf((FILE *)user_data, "       [%d] 0x%" PRIx64 ", type: %d, name: %s\n", obj,
-                callback_data->pObjects[obj].objectHandle, callback_data->pObjects[obj].objectType,
-                callback_data->pObjects[obj].pObjectName);
+        msg_buffer << "        [" << obj << "] " << std::hex << std::showbase
+                   << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
+                   << callback_data->pObjects[obj].objectType
+                   << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
+                   << "\n";
     }
+    const std::string tmp = msg_buffer.str();
+    const char *cstr = tmp.c_str();
+    fprintf((FILE *)user_data, "%s", cstr);
     fflush((FILE *)user_data);
 
+#if defined __ANDROID__
+    LOGCONSOLE("%s", cstr);
+#endif
+
     return false;
 }
 
@@ -997,28 +1081,27 @@
     VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
     const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
 #ifdef WIN32
-    char buf[2048];
+    std::ostringstream msg_buffer;
     char msg_severity[30];
     char msg_type[30];
 
     PrintMessageSeverity(message_severity, msg_severity);
     PrintMessageType(message_type, msg_type);
 
-    size_t buffer_space = sizeof(buf) - 1;
-    size_t remaining_space = buffer_space;
-    _snprintf(buf, sizeof(buf) - 1, "%s(%s / %s): msgNum: %d - %s\n", callback_data->pMessageIdName, msg_severity, msg_type,
-              callback_data->messageIdNumber, callback_data->pMessage);
-    remaining_space = buffer_space - strlen(buf);
-    _snprintf(buf, remaining_space, "    Objects: %d\n", callback_data->objectCount);
+    msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
+               << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
+    msg_buffer << "    Objects: " << callback_data->objectCount << "\n";
+
     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
-        remaining_space = buffer_space - strlen(buf);
-        if (remaining_space > 0) {
-            _snprintf(buf, remaining_space, "       [%d] 0x%" PRIx64 ", type: %d, name: %s\n", obj,
-                      callback_data->pObjects[obj].objectHandle, callback_data->pObjects[obj].objectType,
-                      callback_data->pObjects[obj].pObjectName);
-        }
+        msg_buffer << "       [" << obj << "]  " << std::hex << std::showbase
+                   << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
+                   << callback_data->pObjects[obj].objectType
+                   << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
+                   << "\n";
     }
-    OutputDebugString(buf);
+    const std::string tmp = msg_buffer.str();
+    const char *cstr = tmp.c_str();
+    OutputDebugString(cstr);
 #endif
 
     return false;
@@ -1038,12 +1121,13 @@
 
 static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
                                              const VkDebugUtilsLabelEXT *label_info) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
     if (nullptr != label_info && nullptr != label_info->pLabelName) {
-        auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
-        if (label_iter == report_data->debugUtilsQueueLabels->end()) {
+        auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
+        if (label_iter == report_data->debugUtilsQueueLabels.end()) {
             std::vector<LoggingLabelData> new_queue_labels;
             InsertLabelIntoLog(label_info, new_queue_labels);
-            report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
+            report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
         } else {
             // If the last thing was a label insert, we need to pop it off of the label vector before any
             // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
@@ -1059,8 +1143,9 @@
 }
 
 static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
-    auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
-    if (label_iter != report_data->debugUtilsQueueLabels->end()) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
+    auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
+    if (label_iter != report_data->debugUtilsQueueLabels.end()) {
         // If the last thing was a label insert, we need to pop it off of the label vector before any
         // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
         // temporary location that exists until the next operation occurs.  In this case, a
@@ -1076,12 +1161,13 @@
 
 static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
                                               const VkDebugUtilsLabelEXT *label_info) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
     if (nullptr != label_info && nullptr != label_info->pLabelName) {
-        auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
-        if (label_iter == report_data->debugUtilsQueueLabels->end()) {
+        auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
+        if (label_iter == report_data->debugUtilsQueueLabels.end()) {
             std::vector<LoggingLabelData> new_queue_labels;
             InsertLabelIntoLog(label_info, new_queue_labels);
-            report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
+            report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
         } else {
             // If the last thing was a label insert, we need to pop it off of the label vector before any
             // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
@@ -1100,12 +1186,13 @@
 
 static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
                                            const VkDebugUtilsLabelEXT *label_info) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
     if (nullptr != label_info && nullptr != label_info->pLabelName) {
-        auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
-        if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
+        auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
+        if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
             std::vector<LoggingLabelData> new_cmdbuf_labels;
             InsertLabelIntoLog(label_info, new_cmdbuf_labels);
-            report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
+            report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
         } else {
             // If the last thing was a label insert, we need to pop it off of the label vector before any
             // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
@@ -1121,8 +1208,9 @@
 }
 
 static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
-    auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
-    if (label_iter != report_data->debugUtilsCmdBufLabels->end()) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
+    auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
+    if (label_iter != report_data->debugUtilsCmdBufLabels.end()) {
         // If the last thing was a label insert, we need to pop it off of the label vector before any
         // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
         // temporary location that exists until the next operation occurs.  In this case, a
@@ -1131,19 +1219,23 @@
             report_data->cmdBufLabelHasInsert = false;
             label_iter->second.pop_back();
         }
-        // Now pop the normal item
-        label_iter->second.pop_back();
+        // Guard against unbalanced markers.
+        if (label_iter->second.size() > 0) {
+            // Now pop the normal item
+            label_iter->second.pop_back();
+        }
     }
 }
 
 static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
                                             const VkDebugUtilsLabelEXT *label_info) {
+    std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
     if (nullptr != label_info && nullptr != label_info->pLabelName) {
-        auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
-        if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
+        auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
+        if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
             std::vector<LoggingLabelData> new_cmdbuf_labels;
             InsertLabelIntoLog(label_info, new_cmdbuf_labels);
-            report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
+            report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
         } else {
             // If the last thing was a label insert, we need to pop it off of the label vector before any
             // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
diff --git a/layers/vk_layer_utils.cpp b/layers/vk_layer_utils.cpp
index e25a10e..ed9b0c1 100644
--- a/layers/vk_layer_utils.cpp
+++ b/layers/vk_layer_utils.cpp
@@ -87,6 +87,65 @@
 // If a vk_layer_settings.txt file is present and an application defines a debug callback, both callbacks
 // will be active.  If no vk_layer_settings.txt file is present, creating an application-defined debug
 // callback will cause the default callbacks to be unregisterd and removed.
+VK_LAYER_EXPORT void layer_debug_messenger_actions(debug_report_data *report_data,
+                                                   std::vector<VkDebugUtilsMessengerEXT> &logging_messenger,
+                                                   const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
+    VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
+
+    std::string report_flags_key = layer_identifier;
+    std::string debug_action_key = layer_identifier;
+    std::string log_filename_key = layer_identifier;
+    report_flags_key.append(".report_flags");
+    debug_action_key.append(".debug_action");
+    log_filename_key.append(".log_filename");
+
+    // Initialize layer options
+    VkDebugReportFlagsEXT report_flags = GetLayerOptionFlags(report_flags_key, report_flags_option_definitions, 0);
+    VkLayerDbgActionFlags debug_action = GetLayerOptionFlags(debug_action_key, debug_actions_option_definitions, 0);
+    // Flag as default if these settings are not from a vk_layer_settings.txt file
+    bool default_layer_callback = (debug_action & VK_DBG_LAYER_ACTION_DEFAULT) ? true : false;
+    VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo;
+    memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
+    dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
+    dbgCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+    if (report_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+        dbgCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+    }
+
+    if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) {
+        const char *log_filename = getLayerOption(log_filename_key.c_str());
+        FILE *log_output = getLayerLogOutput(log_filename, layer_identifier);
+        dbgCreateInfo.pfnUserCallback = messenger_log_callback;
+        dbgCreateInfo.pUserData = (void *)log_output;
+        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
+        logging_messenger.push_back(messenger);
+    }
+
+    messenger = VK_NULL_HANDLE;
+
+    if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
+        dbgCreateInfo.pfnUserCallback = messenger_win32_debug_output_msg;
+        dbgCreateInfo.pUserData = NULL;
+        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
+        logging_messenger.push_back(messenger);
+    }
+}
+
+// NOTE: This function has been deprecated, and the above function (layer_debug_messenger_actions) should be
+//       used in its place.
 VK_LAYER_EXPORT void layer_debug_report_actions(debug_report_data *report_data,
                                                 std::vector<VkDebugReportCallbackEXT> &logging_callback,
                                                 const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
@@ -145,63 +204,6 @@
     }
 }
 
-VK_LAYER_EXPORT void layer_debug_messenger_actions(debug_report_data *report_data,
-                                                   std::vector<VkDebugUtilsMessengerEXT> &logging_messenger,
-                                                   const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
-    VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
-
-    std::string report_flags_key = layer_identifier;
-    std::string debug_action_key = layer_identifier;
-    std::string log_filename_key = layer_identifier;
-    report_flags_key.append(".report_flags");
-    debug_action_key.append(".debug_action");
-    log_filename_key.append(".log_filename");
-
-    // Initialize layer options
-    VkDebugReportFlagsEXT report_flags = GetLayerOptionFlags(report_flags_key, report_flags_option_definitions, 0);
-    VkLayerDbgActionFlags debug_action = GetLayerOptionFlags(debug_action_key, debug_actions_option_definitions, 0);
-    // Flag as default if these settings are not from a vk_layer_settings.txt file
-    bool default_layer_callback = (debug_action & VK_DBG_LAYER_ACTION_DEFAULT) ? true : false;
-    VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo;
-    memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
-    dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
-    dbgCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
-    if (report_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
-        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
-    }
-    if (report_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
-        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
-    }
-    if (report_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
-        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
-        dbgCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
-    }
-    if (report_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
-        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
-    }
-    if (report_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
-        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
-    }
-
-    if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) {
-        const char *log_filename = getLayerOption(log_filename_key.c_str());
-        FILE *log_output = getLayerLogOutput(log_filename, layer_identifier);
-        dbgCreateInfo.pfnUserCallback = messenger_log_callback;
-        dbgCreateInfo.pUserData = (void *)log_output;
-        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
-        logging_messenger.push_back(messenger);
-    }
-
-    messenger = VK_NULL_HANDLE;
-
-    if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
-        dbgCreateInfo.pfnUserCallback = messenger_win32_debug_output_msg;
-        dbgCreateInfo.pUserData = NULL;
-        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
-        logging_messenger.push_back(messenger);
-    }
-}
-
 VK_LAYER_EXPORT VkLayerInstanceCreateInfo *get_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func) {
     VkLayerInstanceCreateInfo *chain_info = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext;
     while (chain_info && !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && chain_info->function == func)) {
diff --git a/layers/vk_layer_utils.h b/layers/vk_layer_utils.h
index 710cc78..41bc7fc 100644
--- a/layers/vk_layer_utils.h
+++ b/layers/vk_layer_utils.h
@@ -114,6 +114,8 @@
 VK_LAYER_EXPORT VkLayerInstanceCreateInfo *get_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func);
 VK_LAYER_EXPORT VkLayerDeviceCreateInfo *get_chain_info(const VkDeviceCreateInfo *pCreateInfo, VkLayerFunction func);
 
+static inline bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
+
 extern "C" {
 #endif
 
diff --git a/layers/vk_validation_error_messages.h b/layers/vk_validation_error_messages.h
index 27f86c5..1d3a0a7 100644
--- a/layers/vk_validation_error_messages.h
+++ b/layers/vk_validation_error_messages.h
@@ -1,10 +1,12 @@
-/* THIS FILE IS GENERATED.  DO NOT EDIT. */
-/* (scripts/vk_validation_stats.py) */
+/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */
+/* Vulkan specification version: 1.1.102 */
+/* Header generated: 2019-03-06 12:07:54 */
+
 /*
  * Vulkan
  *
- * Copyright (c) 2016-2018 Google Inc.
- * Copyright (c) 2016-2018 LunarG, Inc.
+ * Copyright (c) 2016-2019 Google Inc.
+ * Copyright (c) 2016-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,15 +36,25 @@
 } vuid_spec_text_pair;
 
 static const vuid_spec_text_pair vuid_spec_text[] = {
-    {"VUID-VkAccelerationStructureCreateInfoNVX-flags-parameter", "flags must be a valid combination of VkBuildAccelerationStructureFlagBitsNVX values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-flags-parameter)"},
-    {"VUID-VkAccelerationStructureCreateInfoNVX-geometryCount-02239", "geometryCount must be less than or equal to VkPhysicalDeviceRaytracingPropertiesNVX::maxGeometryCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-geometryCount-02239)"},
-    {"VUID-VkAccelerationStructureCreateInfoNVX-pGeometries-parameter", "If geometryCount is not 0, pGeometries must be a valid pointer to an array of geometryCount valid VkGeometryNVX structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-pGeometries-parameter)"},
-    {"VUID-VkAccelerationStructureCreateInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-pNext-pNext)"},
-    {"VUID-VkAccelerationStructureCreateInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-sType-sType)"},
-    {"VUID-VkAccelerationStructureCreateInfoNVX-type-parameter", "type must be a valid VkAccelerationStructureTypeNVX value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNVX-type-parameter)"},
-    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-accelerationStructure-parameter)"},
-    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-pNext-pNext)"},
-    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNVX-sType-sType)"},
+    {"VUID-VkAccelerationStructureCreateInfoNV-compactedSize-02421", "If compactedSize is not 0 then both info.geometryCount and info.instanceCount must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNV-compactedSize-02421)"},
+    {"VUID-VkAccelerationStructureCreateInfoNV-info-parameter", "info must be a valid VkAccelerationStructureInfoNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNV-info-parameter)"},
+    {"VUID-VkAccelerationStructureCreateInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNV-pNext-pNext)"},
+    {"VUID-VkAccelerationStructureCreateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureCreateInfoNV-sType-sType)"},
+    {"VUID-VkAccelerationStructureInfoNV-flags-02592", "If flags has the VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV bit set, then it must not have the VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-flags-02592)"},
+    {"VUID-VkAccelerationStructureInfoNV-flags-parameter", "flags must be a valid combination of VkBuildAccelerationStructureFlagBitsNV values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-flags-parameter)"},
+    {"VUID-VkAccelerationStructureInfoNV-geometryCount-02422", "geometryCount must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-geometryCount-02422)"},
+    {"VUID-VkAccelerationStructureInfoNV-instanceCount-02423", "instanceCount must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxInstanceCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-instanceCount-02423)"},
+    {"VUID-VkAccelerationStructureInfoNV-maxTriangleCount-02424", "The total number of triangles in all geometries must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxTriangleCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-maxTriangleCount-02424)"},
+    {"VUID-VkAccelerationStructureInfoNV-pGeometries-parameter", "If geometryCount is not 0, pGeometries must be a valid pointer to an array of geometryCount valid VkGeometryNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-pGeometries-parameter)"},
+    {"VUID-VkAccelerationStructureInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-pNext-pNext)"},
+    {"VUID-VkAccelerationStructureInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-sType-sType)"},
+    {"VUID-VkAccelerationStructureInfoNV-type-02425", "If type is VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV then geometryCount must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-type-02425)"},
+    {"VUID-VkAccelerationStructureInfoNV-type-02426", "If type is VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV then instanceCount must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-type-02426)"},
+    {"VUID-VkAccelerationStructureInfoNV-type-parameter", "type must be a valid VkAccelerationStructureTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureInfoNV-type-parameter)"},
+    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNV-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNV-accelerationStructure-parameter)"},
+    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNV-pNext-pNext)"},
+    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNV-sType-sType)"},
+    {"VUID-VkAccelerationStructureMemoryRequirementsInfoNV-type-parameter", "type must be a valid VkAccelerationStructureMemoryRequirementsTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAccelerationStructureMemoryRequirementsInfoNV-type-parameter)"},
     {"VUID-VkAcquireNextImageInfoKHR-commonparent", "Each of fence, semaphore, and swapchain that are valid handles must have been created, allocated, or retrieved from the same VkInstance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAcquireNextImageInfoKHR-commonparent)"},
     {"VUID-VkAcquireNextImageInfoKHR-deviceMask-01290", "deviceMask must be a valid device mask (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAcquireNextImageInfoKHR-deviceMask-01290)"},
     {"VUID-VkAcquireNextImageInfoKHR-deviceMask-01291", "deviceMask must not be zero (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAcquireNextImageInfoKHR-deviceMask-01291)"},
@@ -62,6 +74,8 @@
     {"VUID-VkAllocationCallbacks-pfnInternalAllocation-00635", "If either of pfnInternalAllocation or pfnInternalFree is not NULL, both must be valid callbacks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAllocationCallbacks-pfnInternalAllocation-00635)"},
     {"VUID-VkAllocationCallbacks-pfnReallocation-00633", "pfnReallocation must be a valid pointer to a valid user-defined PFN_vkReallocationFunction (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAllocationCallbacks-pfnReallocation-00633)"},
     {"VUID-VkAndroidHardwareBufferFormatPropertiesANDROID-sType-sType", "sType must be VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidHardwareBufferFormatPropertiesANDROID-sType-sType)"},
+    {"VUID-VkAndroidHardwareBufferPropertiesANDROID-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkAndroidHardwareBufferFormatPropertiesANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidHardwareBufferPropertiesANDROID-pNext-pNext)"},
+    {"VUID-VkAndroidHardwareBufferPropertiesANDROID-sType-sType", "sType must be VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidHardwareBufferPropertiesANDROID-sType-sType)"},
     {"VUID-VkAndroidHardwareBufferUsageANDROID-sType-sType", "sType must be VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidHardwareBufferUsageANDROID-sType-sType)"},
     {"VUID-VkAndroidSurfaceCreateInfoKHR-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidSurfaceCreateInfoKHR-flags-zerobitmask)"},
     {"VUID-VkAndroidSurfaceCreateInfoKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAndroidSurfaceCreateInfoKHR-pNext-pNext)"},
@@ -92,19 +106,24 @@
     {"VUID-VkAttachmentDescription2KHR-stencilLoadOp-parameter", "stencilLoadOp must be a valid VkAttachmentLoadOp value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentDescription2KHR-stencilLoadOp-parameter)"},
     {"VUID-VkAttachmentDescription2KHR-stencilStoreOp-parameter", "stencilStoreOp must be a valid VkAttachmentStoreOp value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentDescription2KHR-stencilStoreOp-parameter)"},
     {"VUID-VkAttachmentDescription2KHR-storeOp-parameter", "storeOp must be a valid VkAttachmentStoreOp value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentDescription2KHR-storeOp-parameter)"},
-    {"VUID-VkAttachmentReference-layout-00857", "layout must not be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference-layout-00857)"},
+    {"VUID-VkAttachmentReference-layout-00857", "If attachment is not VK_ATTACHMENT_UNUSED, layout must not be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference-layout-00857)"},
     {"VUID-VkAttachmentReference-layout-parameter", "layout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference-layout-parameter)"},
-    {"VUID-VkAttachmentReference2KHR-layout-03077", "layout must not be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference2KHR-layout-03077)"},
+    {"VUID-VkAttachmentReference2KHR-layout-03077", "If attachment is not VK_ATTACHMENT_UNUSED, layout must not be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference2KHR-layout-03077)"},
     {"VUID-VkAttachmentReference2KHR-layout-parameter", "layout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference2KHR-layout-parameter)"},
     {"VUID-VkAttachmentReference2KHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentReference2KHR-sType-sType)"},
     {"VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531", "attachmentIndex must be less than the attachmentCount specified in VkRenderPassCreateInfo the render pass specified by VkRenderPassBeginInfo::renderPass was created with (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531)"},
     {"VUID-VkAttachmentSampleLocationsEXT-sampleLocationsInfo-parameter", "sampleLocationsInfo must be a valid VkSampleLocationsInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkAttachmentSampleLocationsEXT-sampleLocationsInfo-parameter)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-accelerationStructure-parameter)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-commonparent", "Both of accelerationStructure, and memory must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-commonparent)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-memory-parameter", "memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-memory-parameter)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-pDeviceIndices-parameter", "If deviceIndexCount is not 0, pDeviceIndices must be a valid pointer to an array of deviceIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-pDeviceIndices-parameter)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-pNext-pNext)"},
-    {"VUID-VkBindAccelerationStructureMemoryInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNVX-sType-sType)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-02450", "accelerationStructure must not already be backed by a memory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-02450)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-parameter)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-commonparent", "Both of accelerationStructure, and memory must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-commonparent)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-memory-02593", "memory must have been allocated using one of the memory types allowed in the memoryTypeBits member of the VkMemoryRequirements structure returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure and type of VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-memory-02593)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-memory-parameter", "memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-memory-parameter)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02451", "memoryOffset must be less than the size of memory (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02451)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02594", "memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure and type of VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-02594)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-pDeviceIndices-parameter", "If deviceIndexCount is not 0, pDeviceIndices must be a valid pointer to an array of deviceIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-pDeviceIndices-parameter)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-pNext-pNext)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-sType-sType)"},
+    {"VUID-VkBindAccelerationStructureMemoryInfoNV-size-02595", "The size member of the VkMemoryRequirements structure returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure and type of VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV must be less than or equal to the size of memory minus memoryOffset (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindAccelerationStructureMemoryInfoNV-size-02595)"},
     {"VUID-VkBindBufferMemoryDeviceGroupInfo-deviceIndexCount-01606", "deviceIndexCount must either be zero or equal to the number of physical devices in the logical device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindBufferMemoryDeviceGroupInfo-deviceIndexCount-01606)"},
     {"VUID-VkBindBufferMemoryDeviceGroupInfo-pDeviceIndices-01607", "All elements of pDeviceIndices must be valid device indices (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindBufferMemoryDeviceGroupInfo-pDeviceIndices-01607)"},
     {"VUID-VkBindBufferMemoryDeviceGroupInfo-pDeviceIndices-parameter", "If deviceIndexCount is not 0, pDeviceIndices must be a valid pointer to an array of deviceIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindBufferMemoryDeviceGroupInfo-pDeviceIndices-parameter)"},
@@ -149,6 +168,8 @@
     {"VUID-VkBindImageMemoryInfo-memory-01614", "The difference of the size of memory and memoryOffset must be greater than or equal to the size member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with the same image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memory-01614)"},
     {"VUID-VkBindImageMemoryInfo-memory-01625", "memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memory-01625)"},
     {"VUID-VkBindImageMemoryInfo-memory-01903", "If the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then image must equal VkMemoryDedicatedAllocateInfo::image and memoryOffset must be zero. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memory-01903)"},
+    {"VUID-VkBindImageMemoryInfo-memory-02630", "If the dedicated allocation image aliasing feature is not enabled, and the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then image must equal VkMemoryDedicatedAllocateInfo::image and memoryOffset must be zero. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memory-02630)"},
+    {"VUID-VkBindImageMemoryInfo-memory-02631", "If the dedicated allocation image aliasing feature is enabled, and the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then memoryOffset must be zero, and image must be either equal to VkMemoryDedicatedAllocateInfo::image or an image that was created using the same parameters in VkImageCreateInfo, with the exception that extent and arrayLayers may differ subject to the following restrictions: every dimension in the extent parameter of the image being bound must be equal to or smaller than the original image for which the allocation was created; and the arrayLayers parameter of the image being bound must be equal to or smaller than the original image for which the allocation was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memory-02631)"},
     {"VUID-VkBindImageMemoryInfo-memoryOffset-01611", "memoryOffset must be less than the size of memory (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memoryOffset-01611)"},
     {"VUID-VkBindImageMemoryInfo-memoryOffset-01613", "memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-memoryOffset-01613)"},
     {"VUID-VkBindImageMemoryInfo-pNext-01615", "If the pNext chain does not include an instance of the VkBindImagePlaneMemoryInfo structure, memory must have been allocated using one of the memory types allowed in the memoryTypeBits member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements2 with image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindImageMemoryInfo-pNext-01615)"},
@@ -185,15 +206,17 @@
     {"VUID-VkBindSparseInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_BIND_SPARSE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBindSparseInfo-sType-sType)"},
     {"VUID-VkBufferCopy-size-01988", "The size must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCopy-size-01988)"},
     {"VUID-VkBufferCreateInfo-None-01888", "If any of the bits VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, or VK_BUFFER_CREATE_SPARSE_ALIASED_BIT are set, VK_BUFFER_CREATE_PROTECTED_BIT must not also be set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-None-01888)"},
+    {"VUID-VkBufferCreateInfo-deviceAddress-02604", "If VkBufferDeviceAddressCreateInfoEXT::deviceAddress is not zero, flags must include VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-deviceAddress-02604)"},
     {"VUID-VkBufferCreateInfo-flags-00915", "If the sparse bindings feature is not enabled, flags must not contain VK_BUFFER_CREATE_SPARSE_BINDING_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-00915)"},
     {"VUID-VkBufferCreateInfo-flags-00916", "If the sparse buffer residency feature is not enabled, flags must not contain VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-00916)"},
     {"VUID-VkBufferCreateInfo-flags-00917", "If the sparse aliased residency feature is not enabled, flags must not contain VK_BUFFER_CREATE_SPARSE_ALIASED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-00917)"},
     {"VUID-VkBufferCreateInfo-flags-00918", "If flags contains VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT or VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, it must also contain VK_BUFFER_CREATE_SPARSE_BINDING_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-00918)"},
     {"VUID-VkBufferCreateInfo-flags-01887", "If the protected memory feature is not enabled, flags must not contain VK_BUFFER_CREATE_PROTECTED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-01887)"},
+    {"VUID-VkBufferCreateInfo-flags-02605", "If flags includes VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT, the bufferDeviceAddressCaptureReplay feature must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-02605)"},
     {"VUID-VkBufferCreateInfo-flags-parameter", "flags must be a valid combination of VkBufferCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-flags-parameter)"},
     {"VUID-VkBufferCreateInfo-pNext-00920", "If the pNext chain contains an instance of VkExternalMemoryBufferCreateInfo, its handleTypes member must only contain bits that are also in VkExternalBufferProperties::externalMemoryProperties.compatibleHandleTypes, as returned by vkGetPhysicalDeviceExternalBufferProperties with pExternalBufferInfo->handleType equal to any one of the handle types specified in VkExternalMemoryBufferCreateInfo::handleTypes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-pNext-00920)"},
     {"VUID-VkBufferCreateInfo-pNext-01571", "If the pNext chain contains an instance of VkDedicatedAllocationBufferCreateInfoNV, and the dedicatedAllocation member of the chained structure is VK_TRUE, then flags must not include VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, or VK_BUFFER_CREATE_SPARSE_ALIASED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-pNext-01571)"},
-    {"VUID-VkBufferCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDedicatedAllocationBufferCreateInfoNV or VkExternalMemoryBufferCreateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-pNext-pNext)"},
+    {"VUID-VkBufferCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkBufferDeviceAddressCreateInfoEXT, VkDedicatedAllocationBufferCreateInfoNV, or VkExternalMemoryBufferCreateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-pNext-pNext)"},
     {"VUID-VkBufferCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-sType-sType)"},
     {"VUID-VkBufferCreateInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-sType-unique)"},
     {"VUID-VkBufferCreateInfo-sharingMode-00913", "If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a valid pointer to an array of queueFamilyIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-sharingMode-00913)"},
@@ -202,8 +225,15 @@
     {"VUID-VkBufferCreateInfo-sharingMode-01419", "If sharingMode is VK_SHARING_MODE_CONCURRENT, each element of pQueueFamilyIndices must be unique and must be less than pQueueFamilyPropertyCount returned by either vkGetPhysicalDeviceQueueFamilyProperties or vkGetPhysicalDeviceQueueFamilyProperties2 for the physicalDevice that was used to create device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-sharingMode-01419)"},
     {"VUID-VkBufferCreateInfo-sharingMode-parameter", "sharingMode must be a valid VkSharingMode value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-sharingMode-parameter)"},
     {"VUID-VkBufferCreateInfo-size-00912", "size must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-size-00912)"},
+    {"VUID-VkBufferCreateInfo-usage-02606", "If usage includes VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT, the bufferDeviceAddress feature must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-usage-02606)"},
     {"VUID-VkBufferCreateInfo-usage-parameter", "usage must be a valid combination of VkBufferUsageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-usage-parameter)"},
     {"VUID-VkBufferCreateInfo-usage-requiredbitmask", "usage must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferCreateInfo-usage-requiredbitmask)"},
+    {"VUID-VkBufferDeviceAddressCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressCreateInfoEXT-sType-sType)"},
+    {"VUID-VkBufferDeviceAddressInfoEXT-buffer-02600", "If buffer is non-sparse and was not created with the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT flag, then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressInfoEXT-buffer-02600)"},
+    {"VUID-VkBufferDeviceAddressInfoEXT-buffer-02601", "buffer must have been created with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressInfoEXT-buffer-02601)"},
+    {"VUID-VkBufferDeviceAddressInfoEXT-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressInfoEXT-buffer-parameter)"},
+    {"VUID-VkBufferDeviceAddressInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressInfoEXT-pNext-pNext)"},
+    {"VUID-VkBufferDeviceAddressInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferDeviceAddressInfoEXT-sType-sType)"},
     {"VUID-VkBufferImageCopy-None-00214", "When copying to the depth aspect of an image subresource, the data in the source buffer must be in the range [0,1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-None-00214)"},
     {"VUID-VkBufferImageCopy-None-01735", "If the calling command's VkImage parameter is a compressed image, or a single-plane, '_422' image format, bufferRowLength must be a multiple of the compressed texel block width (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-None-01735)"},
     {"VUID-VkBufferImageCopy-None-01736", "If the calling command's VkImage parameter is a compressed image, or a single-plane, '_422' image format, bufferImageHeight must be a multiple of the compressed texel block height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-None-01736)"},
@@ -218,10 +248,10 @@
     {"VUID-VkBufferImageCopy-baseArrayLayer-00213", "If the calling command's VkImage parameter is of VkImageType VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of imageSubresource must be 0 and 1, respectively (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-baseArrayLayer-00213)"},
     {"VUID-VkBufferImageCopy-bufferImageHeight-00196", "bufferImageHeight must be 0, or greater than or equal to the height member of imageExtent (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferImageHeight-00196)"},
     {"VUID-VkBufferImageCopy-bufferImageHeight-00204", "If the calling command's VkImage parameter is a compressed image, bufferImageHeight must be a multiple of the compressed texel block height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferImageHeight-00204)"},
-    {"VUID-VkBufferImageCopy-bufferOffset-00193", "If the calling command's VkImage parameter's format is not a depth/stencil format, then bufferOffset must be a multiple of the format's element size (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-00193)"},
+    {"VUID-VkBufferImageCopy-bufferOffset-00193", "If the calling command's VkImage parameter's format is not a depth/stencil format, then bufferOffset must be a multiple of the format's texel block size. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-00193)"},
     {"VUID-VkBufferImageCopy-bufferOffset-00194", "bufferOffset must be a multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-00194)"},
     {"VUID-VkBufferImageCopy-bufferOffset-00206", "If the calling command's VkImage parameter is a compressed image, bufferOffset must be a multiple of the compressed texel block size in bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-00206)"},
-    {"VUID-VkBufferImageCopy-bufferOffset-01558", "If the calling command's VkImage parameter's format is not a depth/stencil format or a multi-planar format, then bufferOffset must be a multiple of the format's element size (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-01558)"},
+    {"VUID-VkBufferImageCopy-bufferOffset-01558", "If the calling command's VkImage parameter's format is not a depth/stencil format or a multi-planar format, then bufferOffset must be a multiple of the format's texel block size. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-01558)"},
     {"VUID-VkBufferImageCopy-bufferOffset-01559", "If the calling command's VkImage parameter's format is a multi-planar format, then bufferOffset must be a multiple of the element size of the compatible format for the format and the aspectMask of the imageSubresource as defined in Compatible formats of planes of multi-planar formats (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-01559)"},
     {"VUID-VkBufferImageCopy-bufferRowLength-00195", "bufferRowLength must be 0, or greater than or equal to the width member of imageExtent (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferRowLength-00195)"},
     {"VUID-VkBufferImageCopy-bufferRowLength-00203", "If the calling command's VkImage parameter is a compressed image, bufferRowLength must be a multiple of the compressed texel block width (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferImageCopy-bufferRowLength-00203)"},
@@ -267,8 +297,8 @@
     {"VUID-VkBufferViewCreateInfo-offset-00931", "If range is not equal to VK_WHOLE_SIZE, the sum of offset and range must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-offset-00931)"},
     {"VUID-VkBufferViewCreateInfo-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-pNext-pNext)"},
     {"VUID-VkBufferViewCreateInfo-range-00928", "If range is not equal to VK_WHOLE_SIZE, range must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-range-00928)"},
-    {"VUID-VkBufferViewCreateInfo-range-00929", "If range is not equal to VK_WHOLE_SIZE, range must be a multiple of the element size of format (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-range-00929)"},
-    {"VUID-VkBufferViewCreateInfo-range-00930", "If range is not equal to VK_WHOLE_SIZE, range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-range-00930)"},
+    {"VUID-VkBufferViewCreateInfo-range-00929", "If range is not equal to VK_WHOLE_SIZE, range must be an integer multiple of the texel block size of format (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-range-00929)"},
+    {"VUID-VkBufferViewCreateInfo-range-00930", "If range is not equal to VK_WHOLE_SIZE, range divided by the texel block size of format, multiplied by the number of texels per texel block for that format (as defined in the Compatible Formats table), must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-range-00930)"},
     {"VUID-VkBufferViewCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkBufferViewCreateInfo-sType-sType)"},
     {"VUID-VkCalibratedTimestampInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCalibratedTimestampInfoEXT-pNext-pNext)"},
     {"VUID-VkCalibratedTimestampInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCalibratedTimestampInfoEXT-sType-sType)"},
@@ -282,30 +312,27 @@
     {"VUID-VkClearAttachment-aspectMask-parameter", "aspectMask must be a valid combination of VkImageAspectFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearAttachment-aspectMask-parameter)"},
     {"VUID-VkClearAttachment-aspectMask-requiredbitmask", "aspectMask must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearAttachment-aspectMask-requiredbitmask)"},
     {"VUID-VkClearAttachment-clearValue-00021", "clearValue must be a valid VkClearValue union (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearAttachment-clearValue-00021)"},
-    {"VUID-VkClearAttachment-commandBuffer-01809", "If commandBuffer is an unprotected command buffer, then the attachment to be cleared must not be a protected image. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearAttachment-commandBuffer-01809)"},
-    {"VUID-VkClearAttachment-commandBuffer-01810", "If commandBuffer is a protected command buffer, then the attachment to be cleared must not be an unprotected image. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearAttachment-commandBuffer-01810)"},
     {"VUID-VkClearDepthStencilValue-depth-00022", "Unless the VK_EXT_depth_range_unrestricted extension is enabled depth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearDepthStencilValue-depth-00022)"},
-    {"VUID-VkClearDepthStencilValue-depth-00022[(VK_EXT_depth_range_unrestricted)]", "Unless the VK_EXT_depth_range_unrestricted extension is enabled depth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearDepthStencilValue-depth-00022)"},
-    {"VUID-VkClearDepthStencilValue-depth-00022[!(VK_EXT_depth_range_unrestricted)]", "depth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearDepthStencilValue-depth-00022)"},
+    {"VUID-VkClearDepthStencilValue-depth-02506", "depth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkClearDepthStencilValue-depth-02506)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-commonparent", "Each of indirectCommandsLayout, objectTable, sequencesCountBuffer, sequencesIndexBuffer, and targetCommandBuffer that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-commonparent)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsLayout-parameter", "indirectCommandsLayout must be a valid VkIndirectCommandsLayoutNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsLayout-parameter)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-01332", "indirectCommandsTokenCount must match the indirectCommandsLayout's tokenCount. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-01332)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-01332", "indirectCommandsTokenCount must match the indirectCommandsLayout's tokenCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-01332)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-arraylength", "indirectCommandsTokenCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-indirectCommandsTokenCount-arraylength)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-objectTable-01331", "The provided objectTable must include all objects referenced by the generation process. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-objectTable-01331)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-objectTable-01331", "The provided objectTable must include all objects referenced by the generation process (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-objectTable-01331)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-objectTable-parameter", "objectTable must be a valid VkObjectTableNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-objectTable-parameter)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-pIndirectCommandsTokens-parameter", "pIndirectCommandsTokens must be a valid pointer to an array of indirectCommandsTokenCount valid VkIndirectCommandsTokenNVX structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-pIndirectCommandsTokens-parameter)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-pNext-pNext)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sType-sType)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01338", "If sequencesCountBuffer is used, its usage flag must have VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01338)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01339", "If sequencesCountBuffer is used, sequencesCountOffset must be aligned to VkDeviceGeneratedCommandsLimitsNVX::minSequenceCountBufferOffsetAlignment. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01339)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01338", "If sequencesCountBuffer is used, its usage flag must have the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01338)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01339", "If sequencesCountBuffer is used, sequencesCountOffset must be aligned to VkDeviceGeneratedCommandsLimitsNVX::minSequenceCountBufferOffsetAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-01339)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-parameter", "If sequencesCountBuffer is not VK_NULL_HANDLE, sequencesCountBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesCountBuffer-parameter)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01340", "If sequencesIndexBuffer is used, its usage flag must have VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01340)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01341", "If sequencesIndexBuffer is used, sequencesIndexOffset must be aligned to VkDeviceGeneratedCommandsLimitsNVX::minSequenceIndexBufferOffsetAlignment. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01341)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01340", "If sequencesIndexBuffer is used, its usage flag must have the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01340)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01341", "If sequencesIndexBuffer is used, sequencesIndexOffset must be aligned to VkDeviceGeneratedCommandsLimitsNVX::minSequenceIndexBufferOffsetAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-01341)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-parameter", "If sequencesIndexBuffer is not VK_NULL_HANDLE, sequencesIndexBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-sequencesIndexBuffer-parameter)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01334", "If targetCommandBuffer is provided, it must have reserved command space. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01334)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01335", "If targetCommandBuffer is provided, the objectTable must match the reservation's objectTable and must have had all referenced objects registered at reservation time. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01335)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01336", "If targetCommandBuffer is provided, the indirectCommandsLayout must match the reservation's indirectCommandsLayout. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01336)"},
-    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01337", "If targetCommandBuffer is provided, the maxSequencesCount must not exceed the reservation's maxSequencesCount. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01337)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01334", "If targetCommandBuffer is provided, it must have reserved command space (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01334)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01335", "If targetCommandBuffer is provided, the objectTable must match the reservation's objectTable and must have had all referenced objects registered at reservation time (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01335)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01336", "If targetCommandBuffer is provided, the indirectCommandsLayout must match the reservation's indirectCommandsLayout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01336)"},
+    {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01337", "If targetCommandBuffer is provided, the maxSequencesCount must not exceed the reservation's maxSequencesCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-01337)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-parameter", "If targetCommandBuffer is not NULL, targetCommandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-targetCommandBuffer-parameter)"},
     {"VUID-VkCmdProcessCommandsInfoNVX-tokenType-01333", "The tokenType member of each entry in the pIndirectCommandsTokens array must match the values used at creation time of indirectCommandsLayout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdProcessCommandsInfoNVX-tokenType-01333)"},
     {"VUID-VkCmdReserveSpaceForCommandsInfoNVX-commonparent", "Both of indirectCommandsLayout, and objectTable must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCmdReserveSpaceForCommandsInfoNVX-commonparent)"},
@@ -366,12 +393,24 @@
     {"VUID-VkComputePipelineCreateInfo-stage-parameter", "stage must be a valid VkPipelineShaderStageCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkComputePipelineCreateInfo-stage-parameter)"},
     {"VUID-VkConditionalRenderingBeginInfoEXT-buffer-01981", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-buffer-01981)"},
     {"VUID-VkConditionalRenderingBeginInfoEXT-buffer-01982", "buffer must have been created with the VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-buffer-01982)"},
+    {"VUID-VkConditionalRenderingBeginInfoEXT-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-buffer-parameter)"},
+    {"VUID-VkConditionalRenderingBeginInfoEXT-flags-parameter", "flags must be a valid combination of VkConditionalRenderingFlagBitsEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-flags-parameter)"},
     {"VUID-VkConditionalRenderingBeginInfoEXT-offset-01983", "offset must be less than the size of buffer by at least 32 bits. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-offset-01983)"},
     {"VUID-VkConditionalRenderingBeginInfoEXT-offset-01984", "offset must be a multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-offset-01984)"},
+    {"VUID-VkConditionalRenderingBeginInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-pNext-pNext)"},
+    {"VUID-VkConditionalRenderingBeginInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkConditionalRenderingBeginInfoEXT-sType-sType)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-AType-parameter", "AType must be a valid VkComponentTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-AType-parameter)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-BType-parameter", "BType must be a valid VkComponentTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-BType-parameter)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-CType-parameter", "CType must be a valid VkComponentTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-CType-parameter)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-DType-parameter", "DType must be a valid VkComponentTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-DType-parameter)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-pNext-pNext)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-sType-sType)"},
+    {"VUID-VkCooperativeMatrixPropertiesNV-scope-parameter", "scope must be a valid VkScopeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCooperativeMatrixPropertiesNV-scope-parameter)"},
     {"VUID-VkCopyDescriptorSet-commonparent", "Both of dstSet, and srcSet must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-commonparent)"},
     {"VUID-VkCopyDescriptorSet-dstArrayElement-00348", "The sum of dstArrayElement and descriptorCount must be less than or equal to the number of array elements in the descriptor set binding specified by dstBinding, and all applicable consecutive bindings, as described by consecutive binding updates (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-dstArrayElement-00348)"},
     {"VUID-VkCopyDescriptorSet-dstBinding-00347", "dstBinding must be a valid binding within dstSet (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-dstBinding-00347)"},
     {"VUID-VkCopyDescriptorSet-dstBinding-02224", "If the descriptor type of the descriptor set binding specified by dstBinding is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, dstArrayElement must be an integer multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-dstBinding-02224)"},
+    {"VUID-VkCopyDescriptorSet-dstBinding-02632", "The type of dstBinding within dstSet must be equal to the type of srcBinding within srcSet (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-dstBinding-02632)"},
     {"VUID-VkCopyDescriptorSet-dstSet-parameter", "dstSet must be a valid VkDescriptorSet handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-dstSet-parameter)"},
     {"VUID-VkCopyDescriptorSet-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-pNext-pNext)"},
     {"VUID-VkCopyDescriptorSet-sType-sType", "sType must be VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkCopyDescriptorSet-sType-sType)"},
@@ -415,10 +454,12 @@
     {"VUID-VkDebugUtilsLabelEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsLabelEXT-pNext-pNext)"},
     {"VUID-VkDebugUtilsLabelEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsLabelEXT-sType-sType)"},
     {"VUID-VkDebugUtilsMessengerCallbackDataEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-flags-zerobitmask)"},
-    {"VUID-VkDebugUtilsMessengerCallbackDataEXT-objectCount-arraylength", "objectCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-objectCount-arraylength)"},
+    {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pCmdBufLabels-parameter", "If cmdBufLabelCount is not 0, pCmdBufLabels must be a valid pointer to an array of cmdBufLabelCount valid VkDebugUtilsLabelEXT structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pCmdBufLabels-parameter)"},
     {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessage-parameter", "pMessage must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessage-parameter)"},
     {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessageIdName-parameter", "If pMessageIdName is not NULL, pMessageIdName must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessageIdName-parameter)"},
     {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pNext-pNext)"},
+    {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pObjects-parameter", "If objectCount is not 0, pObjects must be a valid pointer to an array of objectCount valid VkDebugUtilsObjectNameInfoEXT structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pObjects-parameter)"},
+    {"VUID-VkDebugUtilsMessengerCallbackDataEXT-pQueueLabels-parameter", "If queueLabelCount is not 0, pQueueLabels must be a valid pointer to an array of queueLabelCount valid VkDebugUtilsLabelEXT structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-pQueueLabels-parameter)"},
     {"VUID-VkDebugUtilsMessengerCallbackDataEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCallbackDataEXT-sType-sType)"},
     {"VUID-VkDebugUtilsMessengerCreateInfoEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCreateInfoEXT-flags-zerobitmask)"},
     {"VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter", "messageSeverity must be a valid combination of VkDebugUtilsMessageSeverityFlagBitsEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter)"},
@@ -427,15 +468,13 @@
     {"VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask", "messageType must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask)"},
     {"VUID-VkDebugUtilsMessengerCreateInfoEXT-pfnUserCallback-01914", "pfnUserCallback must be a valid PFN_vkDebugUtilsMessengerCallbackEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCreateInfoEXT-pfnUserCallback-01914)"},
     {"VUID-VkDebugUtilsMessengerCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsMessengerCreateInfoEXT-sType-sType)"},
-    {"VUID-VkDebugUtilsObjectNameInfoEXT-objectHandle-01906", "objectHandle must not be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectHandle-01906)"},
-    {"VUID-VkDebugUtilsObjectNameInfoEXT-objectHandle-01907", "objectHandle must be a Vulkan object of the type associated with objectType as defined in VkObjectType and Vulkan Handle Relationship. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectHandle-01907)"},
-    {"VUID-VkDebugUtilsObjectNameInfoEXT-objectType-01905", "objectType must not be VK_OBJECT_TYPE_UNKNOWN (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectType-01905)"},
+    {"VUID-VkDebugUtilsObjectNameInfoEXT-objectType-02589", "If objectType is VK_OBJECT_TYPE_UNKNOWN, objectHandle must not be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectType-02589)"},
+    {"VUID-VkDebugUtilsObjectNameInfoEXT-objectType-02590", "If objectType is not VK_OBJECT_TYPE_UNKNOWN, objectHandle must be VK_NULL_HANDLE or a valid Vulkan handle of the type associated with objectType as defined in the VkObjectType and Vulkan Handle Relationship table (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectType-02590)"},
     {"VUID-VkDebugUtilsObjectNameInfoEXT-objectType-parameter", "objectType must be a valid VkObjectType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-objectType-parameter)"},
     {"VUID-VkDebugUtilsObjectNameInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-pNext-pNext)"},
     {"VUID-VkDebugUtilsObjectNameInfoEXT-pObjectName-parameter", "If pObjectName is not NULL, pObjectName must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-pObjectName-parameter)"},
     {"VUID-VkDebugUtilsObjectNameInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectNameInfoEXT-sType-sType)"},
-    {"VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01909", "objectHandle must not be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01909)"},
-    {"VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01910", "objectHandle must be a Vulkan object of the type associated with objectType as defined in VkObjectType and Vulkan Handle Relationship. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01910)"},
+    {"VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01910", "objectHandle must be a valid Vulkan handle of the type associated with objectType as defined in the VkObjectType and Vulkan Handle Relationship table (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-objectHandle-01910)"},
     {"VUID-VkDebugUtilsObjectTagInfoEXT-objectType-01908", "objectType must not be VK_OBJECT_TYPE_UNKNOWN (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-objectType-01908)"},
     {"VUID-VkDebugUtilsObjectTagInfoEXT-objectType-parameter", "objectType must be a valid VkObjectType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-objectType-parameter)"},
     {"VUID-VkDebugUtilsObjectTagInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDebugUtilsObjectTagInfoEXT-pNext-pNext)"},
@@ -456,10 +495,6 @@
     {"VUID-VkDedicatedAllocationMemoryAllocateInfoNV-image-00654", "If image is not VK_NULL_HANDLE and VkMemoryAllocateInfo defines a memory import operation, the memory being imported must also be a dedicated image allocation and image must be identical to the image associated with the imported memory. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDedicatedAllocationMemoryAllocateInfoNV-image-00654)"},
     {"VUID-VkDedicatedAllocationMemoryAllocateInfoNV-image-parameter", "If image is not VK_NULL_HANDLE, image must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDedicatedAllocationMemoryAllocateInfoNV-image-parameter)"},
     {"VUID-VkDedicatedAllocationMemoryAllocateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDedicatedAllocationMemoryAllocateInfoNV-sType-sType)"},
-    {"VUID-VkDescriptorAccelerationStructureInfoNVX-accelerationStructureCount-02236", "accelerationStructureCount must be equal to descriptorCount in the extended structure. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorAccelerationStructureInfoNVX-accelerationStructureCount-02236)"},
-    {"VUID-VkDescriptorAccelerationStructureInfoNVX-accelerationStructureCount-arraylength", "accelerationStructureCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorAccelerationStructureInfoNVX-accelerationStructureCount-arraylength)"},
-    {"VUID-VkDescriptorAccelerationStructureInfoNVX-pAccelerationStructures-parameter", "pAccelerationStructures must be a valid pointer to an array of accelerationStructureCount valid VkAccelerationStructureNVX handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorAccelerationStructureInfoNVX-pAccelerationStructures-parameter)"},
-    {"VUID-VkDescriptorAccelerationStructureInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorAccelerationStructureInfoNVX-sType-sType)"},
     {"VUID-VkDescriptorBufferInfo-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-buffer-parameter)"},
     {"VUID-VkDescriptorBufferInfo-offset-00340", "offset must be less than the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340)"},
     {"VUID-VkDescriptorBufferInfo-range-00341", "If range is not equal to VK_WHOLE_SIZE, range must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341)"},
@@ -497,7 +532,7 @@
     {"VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter", "descriptorType must be a valid VkDescriptorType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter)"},
     {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-None-03011", "All bindings with descriptor type VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC must not use VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-None-03011)"},
     {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-bindingCount-03002", "If bindingCount is not zero, bindingCount must equal VkDescriptorSetLayoutCreateInfo::bindingCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-bindingCount-03002)"},
-    {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingInlineUniformBlockUpdateAfterBind-02211", "If VkPhysicalDeviceInlineUniformBlockFeatureEXT::descriptorBindingInlineUniformBlockUpdateAfterBind is not enabled, all bindings with descriptor type VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT must not use VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingInlineUniformBlockUpdateAfterBind-02211)"},
+    {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingInlineUniformBlockUpdateAfterBind-02211", "If VkPhysicalDeviceInlineUniformBlockFeaturesEXT::descriptorBindingInlineUniformBlockUpdateAfterBind is not enabled, all bindings with descriptor type VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT must not use VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingInlineUniformBlockUpdateAfterBind-02211)"},
     {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingPartiallyBound-03013", "If VkPhysicalDeviceDescriptorIndexingFeaturesEXT::descriptorBindingPartiallyBound is not enabled, all elements of pBindingFlags must not include VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingPartiallyBound-03013)"},
     {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingSampledImageUpdateAfterBind-03006", "If VkPhysicalDeviceDescriptorIndexingFeaturesEXT::descriptorBindingSampledImageUpdateAfterBind is not enabled, all bindings with descriptor type VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, or VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE must not use VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingSampledImageUpdateAfterBind-03006)"},
     {"VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingStorageBufferUpdateAfterBind-03008", "If VkPhysicalDeviceDescriptorIndexingFeaturesEXT::descriptorBindingStorageBufferUpdateAfterBind is not enabled, all bindings with descriptor type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER must not use VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingStorageBufferUpdateAfterBind-03008)"},
@@ -549,7 +584,7 @@
     {"VUID-VkDeviceCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-flags-zerobitmask)"},
     {"VUID-VkDeviceCreateInfo-pEnabledFeatures-parameter", "If pEnabledFeatures is not NULL, pEnabledFeatures must be a valid pointer to a valid VkPhysicalDeviceFeatures structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pEnabledFeatures-parameter)"},
     {"VUID-VkDeviceCreateInfo-pNext-00373", "If the pNext chain includes a VkPhysicalDeviceFeatures2 structure, then pEnabledFeatures must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pNext-00373)"},
-    {"VUID-VkDeviceCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDeviceGroupDeviceCreateInfo, VkPhysicalDevice16BitStorageFeatures, VkPhysicalDevice8BitStorageFeaturesKHR, VkPhysicalDeviceASTCDecodeFeaturesEXT, VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT, VkPhysicalDeviceComputeShaderDerivativesFeaturesNV, VkPhysicalDeviceConditionalRenderingFeaturesEXT, VkPhysicalDeviceCornerSampledImageFeaturesNV, VkPhysicalDeviceDescriptorIndexingFeaturesEXT, VkPhysicalDeviceExclusiveScissorFeaturesNV, VkPhysicalDeviceFeatures2, VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV, VkPhysicalDeviceInlineUniformBlockFeaturesEXT, VkPhysicalDeviceMeshShaderFeaturesNV, VkPhysicalDeviceMultiviewFeatures, VkPhysicalDeviceProtectedMemoryFeatures, VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV, VkPhysicalDeviceSamplerYcbcrConversionFeatures, VkPhysicalDeviceShaderAtomicInt64FeaturesKHR, VkPhysicalDeviceShaderDrawParameterFeatures, VkPhysicalDeviceShaderImageFootprintFeaturesNV, VkPhysicalDeviceShadingRateImageFeaturesNV, VkPhysicalDeviceTransformFeedbackFeaturesEXT, VkPhysicalDeviceVariablePointerFeatures, VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT, or VkPhysicalDeviceVulkanMemoryModelFeaturesKHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pNext-pNext)"},
+    {"VUID-VkDeviceCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDeviceGroupDeviceCreateInfo, VkDeviceMemoryOverallocationCreateInfoAMD, VkPhysicalDevice16BitStorageFeatures, VkPhysicalDevice8BitStorageFeaturesKHR, VkPhysicalDeviceASTCDecodeFeaturesEXT, VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT, VkPhysicalDeviceBufferAddressFeaturesEXT, VkPhysicalDeviceComputeShaderDerivativesFeaturesNV, VkPhysicalDeviceConditionalRenderingFeaturesEXT, VkPhysicalDeviceCooperativeMatrixFeaturesNV, VkPhysicalDeviceCornerSampledImageFeaturesNV, VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV, VkPhysicalDeviceDepthClipEnableFeaturesEXT, VkPhysicalDeviceDescriptorIndexingFeaturesEXT, VkPhysicalDeviceExclusiveScissorFeaturesNV, VkPhysicalDeviceFeatures2, VkPhysicalDeviceFloat16Int8FeaturesKHR, VkPhysicalDeviceFragmentDensityMapFeaturesEXT, VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV, VkPhysicalDeviceInlineUniformBlockFeaturesEXT, VkPhysicalDeviceMemoryPriorityFeaturesEXT, VkPhysicalDeviceMeshShaderFeaturesNV, VkPhysicalDeviceMultiviewFeatures, VkPhysicalDeviceProtectedMemoryFeatures, VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV, VkPhysicalDeviceSamplerYcbcrConversionFeatures, VkPhysicalDeviceScalarBlockLayoutFeaturesEXT, VkPhysicalDeviceShaderAtomicInt64FeaturesKHR, VkPhysicalDeviceShaderDrawParameterFeatures, VkPhysicalDeviceShaderImageFootprintFeaturesNV, VkPhysicalDeviceShadingRateImageFeaturesNV, VkPhysicalDeviceTransformFeedbackFeaturesEXT, VkPhysicalDeviceVariablePointerFeatures, VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT, VkPhysicalDeviceVulkanMemoryModelFeaturesKHR, or VkPhysicalDeviceYcbcrImageArraysFeaturesEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pNext-pNext)"},
     {"VUID-VkDeviceCreateInfo-pQueueCreateInfos-parameter", "pQueueCreateInfos must be a valid pointer to an array of queueCreateInfoCount valid VkDeviceQueueCreateInfo structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-pQueueCreateInfos-parameter)"},
     {"VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374", "ppEnabledExtensionNames must not contain both VK_KHR_maintenance1 and VK_AMD_negative_viewport_height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374)"},
     {"VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840", "ppEnabledExtensionNames must not contain VK_AMD_negative_viewport_height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840)"},
@@ -607,6 +642,8 @@
     {"VUID-VkDeviceGroupSwapchainCreateInfoKHR-modes-parameter", "modes must be a valid combination of VkDeviceGroupPresentModeFlagBitsKHR values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceGroupSwapchainCreateInfoKHR-modes-parameter)"},
     {"VUID-VkDeviceGroupSwapchainCreateInfoKHR-modes-requiredbitmask", "modes must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceGroupSwapchainCreateInfoKHR-modes-requiredbitmask)"},
     {"VUID-VkDeviceGroupSwapchainCreateInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceGroupSwapchainCreateInfoKHR-sType-sType)"},
+    {"VUID-VkDeviceMemoryOverallocationCreateInfoAMD-overallocationBehavior-parameter", "overallocationBehavior must be a valid VkMemoryOverallocationBehaviorAMD value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceMemoryOverallocationCreateInfoAMD-overallocationBehavior-parameter)"},
+    {"VUID-VkDeviceMemoryOverallocationCreateInfoAMD-sType-sType", "sType must be VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceMemoryOverallocationCreateInfoAMD-sType-sType)"},
     {"VUID-VkDeviceQueueCreateInfo-flags-parameter", "flags must be a valid combination of VkDeviceQueueCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceQueueCreateInfo-flags-parameter)"},
     {"VUID-VkDeviceQueueCreateInfo-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkDeviceQueueGlobalPriorityCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceQueueCreateInfo-pNext-pNext)"},
     {"VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383", "Each element of pQueuePriorities must be between 0.0 and 1.0 inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383)"},
@@ -671,7 +708,6 @@
     {"VUID-VkDrawIndirectCommand-None-00500", "For a given vertex buffer binding, any attribute data fetched must be entirely contained within the corresponding vertex buffer binding, as described in Vertex Input Description (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDrawIndirectCommand-None-00500)"},
     {"VUID-VkDrawIndirectCommand-firstInstance-00501", "If the drawIndirectFirstInstance feature is not enabled, firstInstance must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDrawIndirectCommand-firstInstance-00501)"},
     {"VUID-VkDrawMeshTasksIndirectCommandNV-taskCount-02175", "taskCount must be less than or equal to VkPhysicalDeviceMeshShaderPropertiesNV::maxDrawMeshTasksCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDrawMeshTasksIndirectCommandNV-taskCount-02175)"},
-    {"VUID-VkDrmFormatModifierPropertiesListEXT-pDrmFormatModifierProperties-parameter", "If drmFormatModifierCount is not 0, and pDrmFormatModifierProperties is not NULL, pDrmFormatModifierProperties must be a valid pointer to an array of drmFormatModifierCount VkDrmFormatModifierPropertiesEXT structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDrmFormatModifierPropertiesListEXT-pDrmFormatModifierProperties-parameter)"},
     {"VUID-VkDrmFormatModifierPropertiesListEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkDrmFormatModifierPropertiesListEXT-sType-sType)"},
     {"VUID-VkEventCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkEventCreateInfo-flags-zerobitmask)"},
     {"VUID-VkEventCreateInfo-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkEventCreateInfo-pNext-pNext)"},
@@ -735,6 +771,8 @@
     {"VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter", "handleType must be a valid VkExternalFenceHandleTypeFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter)"},
     {"VUID-VkFenceGetWin32HandleInfoKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFenceGetWin32HandleInfoKHR-pNext-pNext)"},
     {"VUID-VkFenceGetWin32HandleInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFenceGetWin32HandleInfoKHR-sType-sType)"},
+    {"VUID-VkFilterCubicImageViewImageFormatPropertiesEXT-pNext-02627", "If the pNext chain of the VkImageFormatProperties2 structure contains an instance of VkFilterCubicImageViewImageFormatPropertiesEXT, the pNext chain of the VkPhysicalDeviceImageFormatInfo2 structure must contain an instance of VkPhysicalDeviceImageViewImageFormatInfoEXT with an imageViewType that is compatible with imageType. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFilterCubicImageViewImageFormatPropertiesEXT-pNext-02627)"},
+    {"VUID-VkFilterCubicImageViewImageFormatPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFilterCubicImageViewImageFormatPropertiesEXT-sType-sType)"},
     {"VUID-VkFormatProperties2-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkDrmFormatModifierPropertiesListEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFormatProperties2-pNext-pNext)"},
     {"VUID-VkFormatProperties2-sType-sType", "sType must be VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFormatProperties2-sType-sType)"},
     {"VUID-VkFramebufferCreateInfo-attachmentCount-00876", "attachmentCount must be equal to the attachment count specified in renderPass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-attachmentCount-00876)"},
@@ -745,7 +783,6 @@
     {"VUID-VkFramebufferCreateInfo-layers-00889", "layers must be greater than 0. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-layers-00889)"},
     {"VUID-VkFramebufferCreateInfo-layers-00890", "layers must be less than or equal to VkPhysicalDeviceLimits::maxFramebufferLayers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-layers-00890)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00877", "Each element of pAttachments that is used as a color attachment or resolve attachment by renderPass must have been created with a usage value including VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00877)"},
-    {"VUID-VkFramebufferCreateInfo-pAttachments-00878", "Each element of pAttachments that is used as a depth/stencil attachment by renderPass must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00878)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00879", "Each element of pAttachments that is used as an input attachment by renderPass must have been created with a usage value including VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00879)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00880", "Each element of pAttachments must have been created with an VkFormat value that matches the VkFormat specified by the corresponding VkAttachmentDescription in renderPass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00880)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00881", "Each element of pAttachments must have been created with a samples value that matches the samples value specified by the corresponding VkAttachmentDescription in renderPass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00881)"},
@@ -753,33 +790,55 @@
     {"VUID-VkFramebufferCreateInfo-pAttachments-00883", "Each element of pAttachments must only specify a single mip level (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00883)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00884", "Each element of pAttachments must have been created with the identity swizzle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00884)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-00891", "Each element of pAttachments that is a 2D or 2D array image view taken from a 3D image must not be a depth/stencil format (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00891)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02552", "Each element of pAttachments that is used as a fragment density map attachment by renderPass must not have been created with a flags value including VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02552)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02554", "Each element of pAttachments must have dimensions at least as large as the corresponding framebuffer dimension except for any element that is referenced by fragmentDensityMapAttachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02554)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02555", "An element of pAttachments that is referenced by fragmentDensityMapAttachment must have a width at least as large as the ceiling of width/maxFragmentDensityTexelSize.width (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02555)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02556", "An element of pAttachments that is referenced by fragmentDensityMapAttachment must have a height at least as large as the ceiling of height/maxFragmentDensityTexelSize.height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02556)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02633", "Each element of pAttachments that is used as a depth/stencil attachment by renderPass must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02633)"},
+    {"VUID-VkFramebufferCreateInfo-pAttachments-02634", "Each element of pAttachments that is used as a depth/stencil resolve attachment by renderPass must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02634)"},
     {"VUID-VkFramebufferCreateInfo-pAttachments-parameter", "If attachmentCount is not 0, pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-parameter)"},
     {"VUID-VkFramebufferCreateInfo-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pNext-pNext)"},
+    {"VUID-VkFramebufferCreateInfo-renderPass-02531", "If renderPass was specified with non-zero view masks, layers must be greater than or equal to the greatest position of any bit included in any of those view masks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-renderPass-02531)"},
+    {"VUID-VkFramebufferCreateInfo-renderPass-02553", "If renderPass has a fragment density map attachment and non-subsample image feature is not enabled, each element of pAttachments must have been created with a flags value including VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT unless that element is the fragment density map attachment. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-renderPass-02553)"},
     {"VUID-VkFramebufferCreateInfo-renderPass-parameter", "renderPass must be a valid VkRenderPass handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-renderPass-parameter)"},
     {"VUID-VkFramebufferCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-sType-sType)"},
     {"VUID-VkFramebufferCreateInfo-width-00885", "width must be greater than 0. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-width-00885)"},
     {"VUID-VkFramebufferCreateInfo-width-00886", "width must be less than or equal to VkPhysicalDeviceLimits::maxFramebufferWidth (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-width-00886)"},
-    {"VUID-VkGeometryAABBNVX-aabbData-parameter", "If aabbData is not VK_NULL_HANDLE, aabbData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNVX-aabbData-parameter)"},
-    {"VUID-VkGeometryAABBNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNVX-pNext-pNext)"},
-    {"VUID-VkGeometryAABBNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNVX-sType-sType)"},
-    {"VUID-VkGeometryDataNVX-aabbs-parameter", "aabbs must be a valid VkGeometryAABBNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryDataNVX-aabbs-parameter)"},
-    {"VUID-VkGeometryDataNVX-triangles-parameter", "triangles must be a valid VkGeometryTrianglesNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryDataNVX-triangles-parameter)"},
-    {"VUID-VkGeometryNVX-flags-parameter", "flags must be a valid combination of VkGeometryFlagBitsNVX values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNVX-flags-parameter)"},
-    {"VUID-VkGeometryNVX-geometry-parameter", "geometry must be a valid VkGeometryDataNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNVX-geometry-parameter)"},
-    {"VUID-VkGeometryNVX-geometryType-parameter", "geometryType must be a valid VkGeometryTypeNVX value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNVX-geometryType-parameter)"},
-    {"VUID-VkGeometryNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNVX-pNext-pNext)"},
-    {"VUID-VkGeometryNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNVX-sType-sType)"},
-    {"VUID-VkGeometryTrianglesNVX-commonparent", "Each of indexData, transformData, and vertexData that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-commonparent)"},
-    {"VUID-VkGeometryTrianglesNVX-indexData-parameter", "If indexData is not VK_NULL_HANDLE, indexData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-indexData-parameter)"},
-    {"VUID-VkGeometryTrianglesNVX-indexType-parameter", "indexType must be a valid VkIndexType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-indexType-parameter)"},
-    {"VUID-VkGeometryTrianglesNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-pNext-pNext)"},
-    {"VUID-VkGeometryTrianglesNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-sType-sType)"},
-    {"VUID-VkGeometryTrianglesNVX-transformData-parameter", "If transformData is not VK_NULL_HANDLE, transformData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-transformData-parameter)"},
-    {"VUID-VkGeometryTrianglesNVX-vertexData-parameter", "If vertexData is not VK_NULL_HANDLE, vertexData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-vertexData-parameter)"},
-    {"VUID-VkGeometryTrianglesNVX-vertexFormat-parameter", "vertexFormat must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNVX-vertexFormat-parameter)"},
+    {"VUID-VkGeometryAABBNV-aabbData-parameter", "If aabbData is not VK_NULL_HANDLE, aabbData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-aabbData-parameter)"},
+    {"VUID-VkGeometryAABBNV-offset-02439", "offset must be less than the size of aabbData (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-offset-02439)"},
+    {"VUID-VkGeometryAABBNV-offset-02440", "offset must be a multiple of 8 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-offset-02440)"},
+    {"VUID-VkGeometryAABBNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-pNext-pNext)"},
+    {"VUID-VkGeometryAABBNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-sType-sType)"},
+    {"VUID-VkGeometryAABBNV-stride-02441", "stride must be a multiple of 8 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryAABBNV-stride-02441)"},
+    {"VUID-VkGeometryDataNV-aabbs-parameter", "aabbs must be a valid VkGeometryAABBNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryDataNV-aabbs-parameter)"},
+    {"VUID-VkGeometryDataNV-triangles-parameter", "triangles must be a valid VkGeometryTrianglesNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryDataNV-triangles-parameter)"},
+    {"VUID-VkGeometryNV-flags-parameter", "flags must be a valid combination of VkGeometryFlagBitsNV values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNV-flags-parameter)"},
+    {"VUID-VkGeometryNV-geometry-parameter", "geometry must be a valid VkGeometryDataNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNV-geometry-parameter)"},
+    {"VUID-VkGeometryNV-geometryType-parameter", "geometryType must be a valid VkGeometryTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNV-geometryType-parameter)"},
+    {"VUID-VkGeometryNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNV-pNext-pNext)"},
+    {"VUID-VkGeometryNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryNV-sType-sType)"},
+    {"VUID-VkGeometryTrianglesNV-commonparent", "Each of indexData, transformData, and vertexData that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-commonparent)"},
+    {"VUID-VkGeometryTrianglesNV-indexCount-02436", "indexCount must be 0 if indexType is VK_INDEX_TYPE_NONE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexCount-02436)"},
+    {"VUID-VkGeometryTrianglesNV-indexData-02434", "indexData must be VK_NULL_HANDLE if indexType is VK_INDEX_TYPE_NONE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexData-02434)"},
+    {"VUID-VkGeometryTrianglesNV-indexData-02435", "indexData must be a valid VkBuffer handle if indexType is not VK_INDEX_TYPE_NONE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexData-02435)"},
+    {"VUID-VkGeometryTrianglesNV-indexData-parameter", "If indexData is not VK_NULL_HANDLE, indexData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexData-parameter)"},
+    {"VUID-VkGeometryTrianglesNV-indexOffset-02431", "indexOffset must be less than the size of indexData (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexOffset-02431)"},
+    {"VUID-VkGeometryTrianglesNV-indexOffset-02432", "indexOffset must be a multiple of the element size of indexType (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexOffset-02432)"},
+    {"VUID-VkGeometryTrianglesNV-indexType-02433", "indexType must be VK_INDEX_TYPE_UINT16, VK_INDEX_TYPE_UINT32, or VK_INDEX_TYPE_NONE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexType-02433)"},
+    {"VUID-VkGeometryTrianglesNV-indexType-parameter", "indexType must be a valid VkIndexType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-indexType-parameter)"},
+    {"VUID-VkGeometryTrianglesNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-pNext-pNext)"},
+    {"VUID-VkGeometryTrianglesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-sType-sType)"},
+    {"VUID-VkGeometryTrianglesNV-transformData-parameter", "If transformData is not VK_NULL_HANDLE, transformData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-transformData-parameter)"},
+    {"VUID-VkGeometryTrianglesNV-transformOffset-02437", "transformOffset must be less than the size of transformData (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-transformOffset-02437)"},
+    {"VUID-VkGeometryTrianglesNV-transformOffset-02438", "transformOffset must be a multiple of 16 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-transformOffset-02438)"},
+    {"VUID-VkGeometryTrianglesNV-vertexData-parameter", "If vertexData is not VK_NULL_HANDLE, vertexData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-vertexData-parameter)"},
+    {"VUID-VkGeometryTrianglesNV-vertexFormat-02430", "vertexFormat must be one of VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16_SNORM, or VK_FORMAT_R16G16B16_SNORM (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-vertexFormat-02430)"},
+    {"VUID-VkGeometryTrianglesNV-vertexFormat-parameter", "vertexFormat must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-vertexFormat-parameter)"},
+    {"VUID-VkGeometryTrianglesNV-vertexOffset-02428", "vertexOffset must be less than the size of vertexData (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-vertexOffset-02428)"},
+    {"VUID-VkGeometryTrianglesNV-vertexOffset-02429", "vertexOffset must be a multiple of the component size of vertexFormat (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGeometryTrianglesNV-vertexOffset-02429)"},
     {"VUID-VkGraphicsPipelineCreateInfo-None-02322", "If there are any mesh shader stages in the pipeline there must not be any shader stage in the pipeline with a Xfb execution mode. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-None-02322)"},
     {"VUID-VkGraphicsPipelineCreateInfo-attachmentCount-00746", "If rasterization is not disabled and the subpass uses color attachments, the attachmentCount member of pColorBlendState must be equal to the colorAttachmentCount used to create subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-attachmentCount-00746)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-blendEnable-02023", "If rasterization is not disabled and the subpass uses color attachments, then for each color attachment in the subpass the blendEnable member of the corresponding element of the pAttachment member of pColorBlendState must be VK_FALSE if the attached image's format features does not contain the VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-blendEnable-02023)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-blendEnable-02023", "If rasterization is not disabled and the subpass uses color attachments, then for each color attachment in the subpass the blendEnable member of the corresponding element of the pAttachment member of pColorBlendState must be VK_FALSE if the attached image's format features does not contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-blendEnable-02023)"},
     {"VUID-VkGraphicsPipelineCreateInfo-commonparent", "Each of basePipelineHandle, layout, and renderPass that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-commonparent)"},
     {"VUID-VkGraphicsPipelineCreateInfo-flags-00722", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineIndex is -1, basePipelineHandle must be a valid handle to a graphics VkPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-flags-00722)"},
     {"VUID-VkGraphicsPipelineCreateInfo-flags-00723", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineHandle is VK_NULL_HANDLE, basePipelineIndex must be a valid index into the calling command's pCreateInfos parameter (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-flags-00723)"},
@@ -796,13 +855,12 @@
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00748", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SCISSOR, the pScissors member of pViewportState must be a valid pointer to an array of pViewportState::scissorCount VkRect2D structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00748)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749", "If the wide lines feature is not enabled, and no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_LINE_WIDTH, the lineWidth member of pRasterizationState must be 1.0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754", "If the depth bias clamping feature is not enabled, no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BIAS, and the depthBiasEnable member of pRasterizationState is VK_TRUE, the depthBiasClamp member of pRasterizationState must be 0.0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755", "If the VK_EXT_depth_range_unrestricted extension is not enabled and no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BOUNDS, and the depthBoundsTestEnable member of pDepthStencilState is VK_TRUE, the minDepthBounds and maxDepthBounds members of pDepthStencilState must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755[(VK_EXT_depth_range_unrestricted)]", "If the VK_EXT_depth_range_unrestricted extension is not enabled and no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BOUNDS, and the depthBoundsTestEnable member of pDepthStencilState is VK_TRUE, the minDepthBounds and maxDepthBounds members of pDepthStencilState must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755[!(VK_EXT_depth_range_unrestricted)]", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BOUNDS, and the depthBoundsTestEnable member of pDepthStencilState is VK_TRUE, the minDepthBounds and maxDepthBounds members of pDepthStencilState must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BOUNDS, and the depthBoundsTestEnable member of pDepthStencilState is VK_TRUE, the minDepthBounds and maxDepthBounds members of pDepthStencilState must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01521", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT, and the sampleLocationsEnable member of a VkPipelineSampleLocationsStateCreateInfoEXT structure chained to the pNext chain of pMultisampleState is VK_TRUE, sampleLocationsInfo.sampleLocationGridSize.width must evenly divide VkMultisamplePropertiesEXT::sampleLocationGridSize.width as returned by vkGetPhysicalDeviceMultisamplePropertiesEXT with a samples parameter equaling rasterizationSamples (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01521)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01522", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT, and the sampleLocationsEnable member of a VkPipelineSampleLocationsStateCreateInfoEXT structure chained to the pNext chain of pMultisampleState is VK_TRUE, sampleLocationsInfo.sampleLocationGridSize.height must evenly divide VkMultisamplePropertiesEXT::sampleLocationGridSize.height as returned by vkGetPhysicalDeviceMultisamplePropertiesEXT with a samples parameter equaling rasterizationSamples (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01522)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01523", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT, and the sampleLocationsEnable member of a VkPipelineSampleLocationsStateCreateInfoEXT structure chained to the pNext chain of pMultisampleState is VK_TRUE, sampleLocationsInfo.sampleLocationsPerPixel must equal rasterizationSamples (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01523)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01715", "If no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV, and the viewportWScalingEnable member of a VkPipelineViewportWScalingStateCreateInfoNV structure, chained to the pNext chain of pViewportState, is VK_TRUE, the pViewportWScalings member of the VkPipelineViewportWScalingStateCreateInfoNV must be a pointer to an array of VkPipelineViewportWScalingStateCreateInfoNV::viewportCount valid VkViewportWScalingNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01715)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510", "If the VK_EXT_depth_range_unrestricted extension is not enabled and no element of the pDynamicStates member of pDynamicState is VK_DYNAMIC_STATE_DEPTH_BOUNDS, and the depthBoundsTestEnable member of pDepthStencilState is VK_TRUE, the minDepthBounds and maxDepthBounds members of pDepthStencilState must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPipelineDiscardRectangleStateCreateInfoEXT or VkPipelineRepresentativeFragmentTestStateCreateInfoNV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pNext-pNext)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pRasterizationState-parameter", "pRasterizationState must be a valid pointer to a valid VkPipelineRasterizationStateCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pRasterizationState-parameter)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-00729", "If pStages includes a tessellation control shader stage, it must include a tessellation evaluation shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00729)"},
@@ -819,7 +877,7 @@
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-00741", "If pStages includes a fragment shader stage, its shader code must not read from any input attachment that is defined as VK_ATTACHMENT_UNUSED in subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00741)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-00742", "The shader code for the entry points identified by pStages, and the rest of the state identified by this structure must adhere to the pipeline linking rules described in the Shader Interfaces chapter (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00742)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-01565", "If pStages includes a fragment shader stage and an input attachment was referenced by the VkRenderPassInputAttachmentAspectCreateInfo at renderPass create time, its shader code must not read from any aspect that was not specified in the aspectMask of the corresponding VkInputAttachmentAspectReference structure. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-01565)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-pStages-02095", "The geometric shader stages provided in pStages must be either from the mesh shading pipeline (stage is VK_SHADER_STAGE_TASK_BIT_NV or VK_SHADER_STAGE_MESH_BIT_NV) or from the primitive shading pipeline (stage is VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, or VK_SHADER_STAGE_GEOEMETRY_BIT). (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-02095)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-pStages-02095", "The geometric shader stages provided in pStages must be either from the mesh shading pipeline (stage is VK_SHADER_STAGE_TASK_BIT_NV or VK_SHADER_STAGE_MESH_BIT_NV) or from the primitive shading pipeline (stage is VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, or VK_SHADER_STAGE_GEOMETRY_BIT). (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-02095)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-02097", "If pStages includes a vertex shader stage, pVertexInputState must be a valid pointer to a valid VkPipelineVertexInputStateCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-02097)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-02098", "If pStages includes a vertex shader stage, pInputAssemblyState must be a valid pointer to a valid VkPipelineInputAssemblyStateCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-02098)"},
     {"VUID-VkGraphicsPipelineCreateInfo-pStages-02317", "The Xfb execution mode can be specified by only one shader stage in pStages (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-pStages-02317)"},
@@ -846,15 +904,17 @@
     {"VUID-VkGraphicsPipelineCreateInfo-stageCount-arraylength", "stageCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-stageCount-arraylength)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-00743", "If rasterization is not disabled and subpass uses a depth/stencil attachment in renderPass that has a layout of VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL in the VkAttachmentReference defined by subpass, the depthWriteEnable member of pDepthStencilState must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00743)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-00744", "If rasterization is not disabled and subpass uses a depth/stencil attachment in renderPass that has a layout of VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL in the VkAttachmentReference defined by subpass, the failOp, passOp and depthFailOp members of each of the front and back members of pDepthStencilState must be VK_STENCIL_OP_KEEP (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00744)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-subpass-00757", "If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of pMultisampleState must be the same as the sample count for those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00757)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-subpass-00757", "If neither the VK_AMD_mixed_attachment_samples nor the VK_NV_framebuffer_mixed_samples extensions are enabled, and if subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of pMultisampleState must be the same as the sample count for those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00757)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-00758", "If subpass does not use any color and/or depth/stencil attachments, then the rasterizationSamples member of pMultisampleState must follow the rules for a zero-attachment subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00758)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-00759", "subpass must be a valid subpass within renderPass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-00759)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01411", "If subpass has a depth/stencil attachment and depth test, stencil test, or depth bounds test are enabled, then the rasterizationSamples member of pMultisampleState must be the same as the sample count of the depth/stencil attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01411)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01412", "If subpass has any color attachments, then the rasterizationSamples member of pMultisampleState must be greater than or equal to the sample count for those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01412)"},
-    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01505", "If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of pMultisampleState must equal the maximum of the sample counts of those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01505)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01411", "If the VK_NV_framebuffer_mixed_samples extension is enabled, and if subpass has a depth/stencil attachment and depth test, stencil test, or depth bounds test are enabled, then the rasterizationSamples member of pMultisampleState must be the same as the sample count of the depth/stencil attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01411)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01412", "If the VK_NV_framebuffer_mixed_samples extension is enabled, and if subpass has any color attachments, then the rasterizationSamples member of pMultisampleState must be greater than or equal to the sample count for those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01412)"},
+    {"VUID-VkGraphicsPipelineCreateInfo-subpass-01505", "If the VK_AMD_mixed_attachment_samples extension is enabled, and if subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of pMultisampleState must equal the maximum of the sample counts of those subpass attachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01505)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-01756", "If rasterization is not disabled and subpass uses a depth/stencil attachment in renderPass that has a layout of VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL in the VkAttachmentReference defined by subpass, the depthWriteEnable member of pDepthStencilState must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01756)"},
     {"VUID-VkGraphicsPipelineCreateInfo-subpass-01757", "If rasterization is not disabled and subpass uses a depth/stencil attachment in renderPass that has a layout of VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL in the VkAttachmentReference defined by subpass, the failOp, passOp and depthFailOp members of each of the front and back members of pDepthStencilState must be VK_STENCIL_OP_KEEP (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-subpass-01757)"},
     {"VUID-VkGraphicsPipelineCreateInfo-topology-00737", "If the topology member of pInputAssembly is VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, pStages must include tessellation shader stages (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-topology-00737)"},
+    {"VUID-VkHdrMetadataEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkHdrMetadataEXT-pNext-pNext)"},
+    {"VUID-VkHdrMetadataEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_HDR_METADATA_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkHdrMetadataEXT-sType-sType)"},
     {"VUID-VkIOSSurfaceCreateInfoMVK-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkIOSSurfaceCreateInfoMVK-flags-zerobitmask)"},
     {"VUID-VkIOSSurfaceCreateInfoMVK-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkIOSSurfaceCreateInfoMVK-pNext-pNext)"},
     {"VUID-VkIOSSurfaceCreateInfoMVK-pView-01316", "pView must be a valid UIView and must be backed by a CALayer instance of type CAMetalLayer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkIOSSurfaceCreateInfoMVK-pView-01316)"},
@@ -924,6 +984,7 @@
     {"VUID-VkImageCopy-srcOffset-00147", "srcOffset.z and (extent.depth + srcOffset.z) must both be greater than or equal to 0 and less than or equal to the source image subresource depth (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCopy-srcOffset-00147)"},
     {"VUID-VkImageCopy-srcOffset-00157", "If the calling command's srcImage is a compressed image, all members of srcOffset must be a multiple of the corresponding dimensions of the compressed texel block (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCopy-srcOffset-00157)"},
     {"VUID-VkImageCopy-srcSubresource-parameter", "srcSubresource must be a valid VkImageSubresourceLayers structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCopy-srcSubresource-parameter)"},
+    {"VUID-VkImageCreateInfo-Format-02536", "If Format is a depth-stencil format and the pNext chain contains an instance of VkImageStencilUsageCreateInfoEXT with its stencilUsage member including VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, extent.width must be less than or equal to VkPhysicalDeviceLimits::maxFramebufferWidth (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-Format-02536)"},
     {"VUID-VkImageCreateInfo-None-01891", "If any of the bits VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT are set, VK_IMAGE_CREATE_PROTECTED_BIT must not also be set. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-None-01891)"},
     {"VUID-VkImageCreateInfo-None-01925", "If any of the bits VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT are set, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT must not also be set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-None-01925)"},
     {"VUID-VkImageCreateInfo-arrayLayers-00948", "arrayLayers must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-arrayLayers-00948)"},
@@ -948,12 +1009,25 @@
     {"VUID-VkImageCreateInfo-flags-02052", "If flags contains VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and imageType is VK_IMAGE_TYPE_2D, extent::width and extent::height must be greater than 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02052)"},
     {"VUID-VkImageCreateInfo-flags-02053", "If flags contains VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and imageType is VK_IMAGE_TYPE_3D, extent::width, extent::height, and extent::depth must be greater than 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02053)"},
     {"VUID-VkImageCreateInfo-flags-02259", "If flags contains VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, then mipLevels must be one, arrayLayers must be one, imageType must be VK_IMAGE_TYPE_2D. and imageCreateMaybeLinear (as defined in Image Creation Limits) must be false. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02259)"},
+    {"VUID-VkImageCreateInfo-flags-02557", "If flags contains VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, imageType must be VK_IMAGE_TYPE_2D (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02557)"},
+    {"VUID-VkImageCreateInfo-flags-02565", "If flags contains VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, tiling must be VK_IMAGE_TILING_OPTIMAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02565)"},
+    {"VUID-VkImageCreateInfo-flags-02566", "If flags contains VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, imageType must be VK_IMAGE_TYPE_2D (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02566)"},
+    {"VUID-VkImageCreateInfo-flags-02567", "If flags contains VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02567)"},
+    {"VUID-VkImageCreateInfo-flags-02568", "If flags contains VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT, mipLevels must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-02568)"},
     {"VUID-VkImageCreateInfo-flags-parameter", "flags must be a valid combination of VkImageCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-flags-parameter)"},
     {"VUID-VkImageCreateInfo-format-00943", "format must not be VK_FORMAT_UNDEFINED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-00943)"},
-    {"VUID-VkImageCreateInfo-format-01574", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-01574)"},
     {"VUID-VkImageCreateInfo-format-01577", "If format is not a multi-planar format, and flags does not include VK_IMAGE_CREATE_ALIAS_BIT, flags must not contain VK_IMAGE_CREATE_DISJOINT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-01577)"},
+    {"VUID-VkImageCreateInfo-format-02534", "If format is a depth-stencil format and the pNext chain contains an instance of VkImageStencilUsageCreateInfoEXT, then its stencilUsage member must only include VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT if usage also includes it (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02534)"},
+    {"VUID-VkImageCreateInfo-format-02535", "If format is a depth-stencil format and the pNext chain contains an instance of VkImageStencilUsageCreateInfoEXT, then its stencilUsage member must only include VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT if usage also includes it (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02535)"},
+    {"VUID-VkImageCreateInfo-format-02537", "If format is a depth-stencil format and the pNext chain contains an instance of VkImageStencilUsageCreateInfoEXT with its stencilUsage member including VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, extent.height must be less than or equal to VkPhysicalDeviceLimits::maxFramebufferHeight (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02537)"},
+    {"VUID-VkImageCreateInfo-format-02538", "If the multisampled storage images feature is not enabled, format is a depth-stencil format and the pNext chain contains an instance of VkImageStencilUsageCreateInfoEXT with its stencilUsage including VK_IMAGE_USAGE_STORAGE_BIT, samples must be VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02538)"},
+    {"VUID-VkImageCreateInfo-format-02561", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views, then mipLevels must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02561)"},
+    {"VUID-VkImageCreateInfo-format-02562", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views, samples must be VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02562)"},
+    {"VUID-VkImageCreateInfo-format-02563", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views, imageType must be VK_IMAGE_TYPE_2D (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02563)"},
+    {"VUID-VkImageCreateInfo-format-02564", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views, arrayLayers must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02564)"},
+    {"VUID-VkImageCreateInfo-format-02653", "If the image format is one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views, and the ycbcrImageArrays feature is not enabled, arrayLayers must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-02653)"},
     {"VUID-VkImageCreateInfo-format-parameter", "format must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-format-parameter)"},
-    {"VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260", "If pame:format is a multi-planar format, and if imageCreateFormatFeatures (as defined in Image Creation Limits) does not contain VK_FORMAT_FEATURE_DISJOINT_BIT, then flags must not contain VK_IMAGE_CREATE_DISJOINT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260)"},
+    {"VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260", "If format is a multi-planar format, and if imageCreateFormatFeatures (as defined in Image Creation Limits) does not contain VK_FORMAT_FEATURE_DISJOINT_BIT, then flags must not contain VK_IMAGE_CREATE_DISJOINT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260)"},
     {"VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251", "Each of the following values (as described in Image Creation Limits) must not be undefined imageCreateMaxMipLevels, imageCreateMaxArrayLayers, imageCreateMaxExtent, and imageCreateSampleCounts. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251)"},
     {"VUID-VkImageCreateInfo-imageType-00954", "If imageType is VK_IMAGE_TYPE_2D and flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, extent.width and extent.height must be equal and arrayLayers must be greater than or equal to 6 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-imageType-00954)"},
     {"VUID-VkImageCreateInfo-imageType-00956", "If imageType is VK_IMAGE_TYPE_1D, both extent.height and extent.depth must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-imageType-00956)"},
@@ -977,18 +1051,22 @@
     {"VUID-VkImageCreateInfo-pNext-00990", "If the pNext chain contains an instance of VkExternalMemoryImageCreateInfo, its handleTypes member must only contain bits that are also in VkExternalImageFormatProperties::externalMemoryProperties.compatibleHandleTypes, as returned by vkGetPhysicalDeviceImageFormatProperties2 with format, imageType, tiling, usage, and flags equal to those in this structure, and with an instance of VkPhysicalDeviceExternalImageFormatInfo in the pNext chain, with a handleType equal to any one of the handle types specified in VkExternalMemoryImageCreateInfo::handleTypes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-00990)"},
     {"VUID-VkImageCreateInfo-pNext-00991", "If the pNext chain contains an instance of VkExternalMemoryImageCreateInfoNV, its handleTypes member must only contain bits that are also in VkExternalImageFormatPropertiesNV::externalMemoryProperties.compatibleHandleTypes, as returned by vkGetPhysicalDeviceExternalImageFormatPropertiesNV with format, imageType, tiling, usage, and flags equal to those in this structure, and with externalHandleType equal to any one of the handle types specified in VkExternalMemoryImageCreateInfoNV::handleTypes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-00991)"},
     {"VUID-VkImageCreateInfo-pNext-01443", "If the pNext chain includes a ifdef::VK_VERSION_1_1,VK_KHR_external_memory[VkExternalMemoryImageCreateInfo] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-01443)"},
-    {"VUID-VkImageCreateInfo-pNext-01892", "If the pNext chain includes a VkExternalMemoryImageCreateInfo structure whose handleTypes member includes VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-01892)"},
-    {"VUID-VkImageCreateInfo-pNext-01893", "If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat member is not 0: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-01893)"},
     {"VUID-VkImageCreateInfo-pNext-01974", "If the pNext chain contains an instance of VkExternalFormatANDROID, and its member externalFormat is non-zero the format must be VK_FORMAT_UNDEFINED. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-01974)"},
     {"VUID-VkImageCreateInfo-pNext-01975", "If the pNext chain does not contain an instance of VkExternalFormatANDROID, or does and its member externalFormat is 0 the format must not be VK_FORMAT_UNDEFINED. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-01975)"},
     {"VUID-VkImageCreateInfo-pNext-02262", "If the pNext chain contains VkImageDrmFormatModifierListCreateInfoEXT or VkImageDrmFormatModifierExplicitCreateInfoEXT, then tiling must be VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02262)"},
-    {"VUID-VkImageCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDedicatedAllocationImageCreateInfoNV, VkExternalFormatANDROID, VkExternalMemoryImageCreateInfo, VkExternalMemoryImageCreateInfoNV, VkImageDrmFormatModifierExplicitCreateInfoEXT, VkImageDrmFormatModifierListCreateInfoEXT, VkImageFormatListCreateInfoKHR, or VkImageSwapchainCreateInfoKHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-pNext)"},
+    {"VUID-VkImageCreateInfo-pNext-02393", "If the pNext chain includes a VkExternalMemoryImageCreateInfo structure whose handleTypes member includes VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, imageType must be VK_IMAGE_TYPE_2D. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02393)"},
+    {"VUID-VkImageCreateInfo-pNext-02394", "If the pNext chain includes a VkExternalMemoryImageCreateInfo structure whose handleTypes member includes VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, mipLevels must either be 1 or equal to the number of levels in the complete mipmap chain based on extent.width, extent.height, and extent.depth. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02394)"},
+    {"VUID-VkImageCreateInfo-pNext-02396", "If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat member is not 0, flags must not include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02396)"},
+    {"VUID-VkImageCreateInfo-pNext-02397", "If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat member is not 0, usage must not include any usages except VK_IMAGE_USAGE_SAMPLED_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02397)"},
+    {"VUID-VkImageCreateInfo-pNext-02398", "If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat member is not 0, tiling must be VK_IMAGE_TILING_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-02398)"},
+    {"VUID-VkImageCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDedicatedAllocationImageCreateInfoNV, VkExternalFormatANDROID, VkExternalMemoryImageCreateInfo, VkExternalMemoryImageCreateInfoNV, VkImageDrmFormatModifierExplicitCreateInfoEXT, VkImageDrmFormatModifierListCreateInfoEXT, VkImageFormatListCreateInfoKHR, VkImageStencilUsageCreateInfoEXT, or VkImageSwapchainCreateInfoKHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-pNext)"},
     {"VUID-VkImageCreateInfo-physicalDeviceCount-01421", "If the logical device was created with VkDeviceGroupDeviceCreateInfo::physicalDeviceCount equal to 1, flags must not contain VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-physicalDeviceCount-01421)"},
     {"VUID-VkImageCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-sType-sType)"},
     {"VUID-VkImageCreateInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-sType-unique)"},
     {"VUID-VkImageCreateInfo-samples-02083", "If usage includes VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, samples must be VK_SAMPLE_COUNT_1_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-samples-02083)"},
     {"VUID-VkImageCreateInfo-samples-02257", "If samples is not VK_SAMPLE_COUNT_1_BIT, then imageType must be VK_IMAGE_TYPE_2D, flags must not contain VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, mipLevels must be equal to 1, and imageCreateMaybeLinear (as defined in Image Creation Limits) must be false, (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-samples-02257)"},
     {"VUID-VkImageCreateInfo-samples-02258", "samples must be a bit value that is set in imageCreateSampleCounts (as defined in Image Creation Limits). (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-samples-02258)"},
+    {"VUID-VkImageCreateInfo-samples-02558", "If samples is not VK_SAMPLE_COUNT_1_BIT, usage must not contain VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-samples-02558)"},
     {"VUID-VkImageCreateInfo-samples-parameter", "samples must be a valid VkSampleCountFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-samples-parameter)"},
     {"VUID-VkImageCreateInfo-sharingMode-00941", "If sharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a valid pointer to an array of queueFamilyIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-sharingMode-00941)"},
     {"VUID-VkImageCreateInfo-sharingMode-00942", "If sharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-sharingMode-00942)"},
@@ -1004,6 +1082,8 @@
     {"VUID-VkImageCreateInfo-usage-00965", "If usage includes VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, extent.height must be less than or equal to VkPhysicalDeviceLimits::maxFramebufferHeight (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-00965)"},
     {"VUID-VkImageCreateInfo-usage-00966", "If usage includes VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, usage must also contain at least one of VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-00966)"},
     {"VUID-VkImageCreateInfo-usage-00968", "If the multisampled storage images feature is not enabled, and usage contains VK_IMAGE_USAGE_STORAGE_BIT, samples must be VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-00968)"},
+    {"VUID-VkImageCreateInfo-usage-02559", "If usage includes VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, extent.width must be less than or equal to the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-02559)"},
+    {"VUID-VkImageCreateInfo-usage-02560", "If usage includes VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, extent.height must be less than or equal to the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-02560)"},
     {"VUID-VkImageCreateInfo-usage-parameter", "usage must be a valid combination of VkImageUsageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-parameter)"},
     {"VUID-VkImageCreateInfo-usage-requiredbitmask", "usage must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageCreateInfo-usage-requiredbitmask)"},
     {"VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268", "For each element of pPlaneLayouts, arrayPitch must be 0 if VkImageCreateInfo::arrayLayers is 1. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268)"},
@@ -1024,7 +1104,7 @@
     {"VUID-VkImageFormatListCreateInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatListCreateInfoKHR-sType-sType)"},
     {"VUID-VkImageFormatListCreateInfoKHR-viewFormatCount-01578", "If viewFormatCount is not 0, all of the formats in the pViewFormats array must be compatible with the format specified in the format field of VkImageCreateInfo, as described in the compatibility table. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatListCreateInfoKHR-viewFormatCount-01578)"},
     {"VUID-VkImageFormatListCreateInfoKHR-viewFormatCount-01580", "If viewFormatCount is not 0, VkImageCreateInfo::format must be in pViewFormats. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatListCreateInfoKHR-viewFormatCount-01580)"},
-    {"VUID-VkImageFormatProperties2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkAndroidHardwareBufferUsageANDROID, VkExternalImageFormatProperties, VkSamplerYcbcrConversionImageFormatProperties, or VkTextureLODGatherFormatPropertiesAMD (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatProperties2-pNext-pNext)"},
+    {"VUID-VkImageFormatProperties2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkAndroidHardwareBufferUsageANDROID, VkExternalImageFormatProperties, VkFilterCubicImageViewImageFormatPropertiesEXT, VkSamplerYcbcrConversionImageFormatProperties, or VkTextureLODGatherFormatPropertiesAMD (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatProperties2-pNext-pNext)"},
     {"VUID-VkImageFormatProperties2-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatProperties2-sType-sType)"},
     {"VUID-VkImageFormatProperties2-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageFormatProperties2-sType-unique)"},
     {"VUID-VkImageMemoryBarrier-dstAccessMask-parameter", "dstAccessMask must be a valid combination of VkAccessFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-dstAccessMask-parameter)"},
@@ -1098,6 +1178,10 @@
     {"VUID-VkImageSparseMemoryRequirementsInfo2-image-parameter", "image must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSparseMemoryRequirementsInfo2-image-parameter)"},
     {"VUID-VkImageSparseMemoryRequirementsInfo2-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSparseMemoryRequirementsInfo2-pNext-pNext)"},
     {"VUID-VkImageSparseMemoryRequirementsInfo2-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSparseMemoryRequirementsInfo2-sType-sType)"},
+    {"VUID-VkImageStencilUsageCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageStencilUsageCreateInfoEXT-sType-sType)"},
+    {"VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-02539", "If stencilUsage includes VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, then bits other than VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, and VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT must not be set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-02539)"},
+    {"VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-parameter", "stencilUsage must be a valid combination of VkImageUsageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-parameter)"},
+    {"VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-requiredbitmask", "stencilUsage must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageStencilUsageCreateInfoEXT-stencilUsage-requiredbitmask)"},
     {"VUID-VkImageSubresource-aspectMask-parameter", "aspectMask must be a valid combination of VkImageAspectFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSubresource-aspectMask-parameter)"},
     {"VUID-VkImageSubresource-aspectMask-requiredbitmask", "aspectMask must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSubresource-aspectMask-requiredbitmask)"},
     {"VUID-VkImageSubresourceLayers-aspectMask-00167", "If aspectMask contains VK_IMAGE_ASPECT_COLOR_BIT, it must not contain either of VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageSubresourceLayers-aspectMask-00167)"},
@@ -1123,7 +1207,8 @@
     {"VUID-VkImageViewASTCDecodeModeEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewASTCDecodeModeEXT-sType-sType)"},
     {"VUID-VkImageViewCreateInfo-None-02273", "The format features of the resultant image view must contain at least one bit. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-None-02273)"},
     {"VUID-VkImageViewCreateInfo-components-parameter", "components must be a valid VkComponentMapping structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-components-parameter)"},
-    {"VUID-VkImageViewCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-flags-zerobitmask)"},
+    {"VUID-VkImageViewCreateInfo-flags-02572", "If dynamic fragment density map feature is not enabled, flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-flags-02572)"},
+    {"VUID-VkImageViewCreateInfo-flags-parameter", "flags must be a valid combination of VkImageViewCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-flags-parameter)"},
     {"VUID-VkImageViewCreateInfo-format-parameter", "format must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-format-parameter)"},
     {"VUID-VkImageViewCreateInfo-image-01003", "If image was not created with VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT then viewType must not be VK_IMAGE_VIEW_TYPE_CUBE or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01003)"},
     {"VUID-VkImageViewCreateInfo-image-01005", "If image was created with VK_IMAGE_TYPE_3D but without VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT set then viewType must not be VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01005)"},
@@ -1140,10 +1225,16 @@
     {"VUID-VkImageViewCreateInfo-image-01760", "If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, and if the format of the image is not a multi-planar format, format must be compatible with the format used to create image, as defined in Format Compatibility Classes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01760)"},
     {"VUID-VkImageViewCreateInfo-image-01761", "If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, but without the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag, and if the format of the image is not a multi-planar format, format must be compatible with the format used to create image, as defined in Format Compatibility Classes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01761)"},
     {"VUID-VkImageViewCreateInfo-image-01762", "If image was not created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, or if the format of the image is a multi-planar format and if subresourceRange.aspectMask is VK_IMAGE_ASPECT_COLOR_BIT, format must be identical to the format used to create image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01762)"},
-    {"VUID-VkImageViewCreateInfo-image-01896", "If image has an external format: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01896)"},
     {"VUID-VkImageViewCreateInfo-image-02085", "image must have been created with a usage value containing at least one of VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, or VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02085)"},
     {"VUID-VkImageViewCreateInfo-image-02086", "If image was created with usage containing VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, viewType must be VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02086)"},
     {"VUID-VkImageViewCreateInfo-image-02087", "If image was created with usage containing VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02087)"},
+    {"VUID-VkImageViewCreateInfo-image-02399", "If image has an external format, format must be VK_FORMAT_UNDEFINED. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02399)"},
+    {"VUID-VkImageViewCreateInfo-image-02400", "If image has an external format, the pNext chain must contain an instance of VkSamplerYcbcrConversionInfo with a conversion object created with the same external format as image. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02400)"},
+    {"VUID-VkImageViewCreateInfo-image-02401", "If image has an external format, all members of components must be VK_COMPONENT_SWIZZLE_IDENTITY. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02401)"},
+    {"VUID-VkImageViewCreateInfo-image-02569", "image must have been created with a usage value containing at least one of VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, or VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02569)"},
+    {"VUID-VkImageViewCreateInfo-image-02570", "image must have been created with a usage value containing at least one of VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, or VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02570)"},
+    {"VUID-VkImageViewCreateInfo-image-02571", "If image was created with usage containing VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, subresourceRange.levelCount must be 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02571)"},
+    {"VUID-VkImageViewCreateInfo-image-02573", "If dynamic fragment density map feature is not enabled and image was created with usage containing VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, flags must not contain any of VK_IMAGE_CREATE_PROTECTED_BIT, VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-02573)"},
     {"VUID-VkImageViewCreateInfo-image-parameter", "image must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-image-parameter)"},
     {"VUID-VkImageViewCreateInfo-pNext-01585", "If a VkImageFormatListCreateInfoKHR structure was included in the pNext chain of the VkImageCreateInfo struct used when creating image and the viewFormatCount field of VkImageFormatListCreateInfoKHR is not zero then format must be one of the formats in VkImageFormatListCreateInfoKHR::pViewFormats. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-pNext-01585)"},
     {"VUID-VkImageViewCreateInfo-pNext-01970", "If the pNext chain contains an instance of VkSamplerYcbcrConversionInfo with a conversion value other than VK_NULL_HANDLE, all members of components must have the value VK_COMPONENT_SWIZZLE_IDENTITY. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-pNext-01970)"},
@@ -1162,14 +1253,25 @@
     {"VUID-VkImageViewCreateInfo-usage-02275", "If usage contains VK_IMAGE_USAGE_STORAGE_BIT, then the image view's format features must contain VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-usage-02275)"},
     {"VUID-VkImageViewCreateInfo-usage-02276", "If usage contains VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, then the image view's format features must contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-usage-02276)"},
     {"VUID-VkImageViewCreateInfo-usage-02277", "If usage contains VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, then the image view's format features must contain VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-usage-02277)"},
+    {"VUID-VkImageViewCreateInfo-usage-02652", "If usage contains VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, then the image view's format features must contain at least one of VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT or VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-usage-02652)"},
     {"VUID-VkImageViewCreateInfo-viewType-01004", "If the image cubemap arrays feature is not enabled, viewType must not be VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-01004)"},
     {"VUID-VkImageViewCreateInfo-viewType-parameter", "viewType must be a valid VkImageViewType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-parameter)"},
+    {"VUID-VkImageViewHandleInfoNVX-commonparent", "Both of imageView, and sampler that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-commonparent)"},
+    {"VUID-VkImageViewHandleInfoNVX-descriptorType-02654", "descriptorType must be VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-descriptorType-02654)"},
+    {"VUID-VkImageViewHandleInfoNVX-descriptorType-parameter", "descriptorType must be a valid VkDescriptorType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-descriptorType-parameter)"},
+    {"VUID-VkImageViewHandleInfoNVX-imageView-02656", "If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE or    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, the image that    imageView was created from must have been created with the    VK_IMAGE_USAGE_SAMPLED_BIT usage bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-imageView-02656)"},
+    {"VUID-VkImageViewHandleInfoNVX-imageView-02657", "If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, the image that imageView was created from must have been created with the VK_IMAGE_USAGE_STORAGE_BIT usage bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-imageView-02657)"},
+    {"VUID-VkImageViewHandleInfoNVX-imageView-parameter", "imageView must be a valid VkImageView handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-imageView-parameter)"},
+    {"VUID-VkImageViewHandleInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-pNext-pNext)"},
+    {"VUID-VkImageViewHandleInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-sType-sType)"},
+    {"VUID-VkImageViewHandleInfoNVX-sampler-02655", "sampler must be a valid VkSampler if descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-sampler-02655)"},
+    {"VUID-VkImageViewHandleInfoNVX-sampler-parameter", "If sampler is not VK_NULL_HANDLE, sampler must be a valid VkSampler handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewHandleInfoNVX-sampler-parameter)"},
     {"VUID-VkImageViewUsageCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewUsageCreateInfo-sType-sType)"},
     {"VUID-VkImageViewUsageCreateInfo-usage-01587", "usage must not include any set bits that were not set in the usage member of the VkImageCreateInfo structure used to create the image this image view is created from. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewUsageCreateInfo-usage-01587)"},
     {"VUID-VkImageViewUsageCreateInfo-usage-parameter", "usage must be a valid combination of VkImageUsageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewUsageCreateInfo-usage-parameter)"},
     {"VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask", "usage must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask)"},
     {"VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01880", "If buffer is not NULL, Android hardware buffers must be supported for import, as reported by VkExternalImageFormatProperties or VkExternalBufferProperties. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01880)"},
-    {"VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881", "If buffer is not NULL, it must be a valid Android hardware buffer object with format and usage compatible with Vulkan as described by VkExternalMemoryHandleTypeFlagBits. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881)"},
+    {"VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881", "If buffer is not NULL, it must be a valid Android hardware buffer object with AHardwareBuffer_Desc::format and AHardwareBuffer_Desc::usage compatible with Vulkan as described in Android Hardware Buffers. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881)"},
     {"VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-parameter", "buffer must be a valid pointer to a AHardwareBuffer value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-parameter)"},
     {"VUID-VkImportAndroidHardwareBufferInfoANDROID-sType-sType", "sType must be VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-sType-sType)"},
     {"VUID-VkImportFenceFdInfoKHR-fd-01541", "fd must obey any requirements listed for handleType in external fence handle types compatibility. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportFenceFdInfoKHR-fd-01541)"},
@@ -1266,7 +1368,7 @@
     {"VUID-VkInputAttachmentAspectReference-aspectMask-requiredbitmask", "aspectMask must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInputAttachmentAspectReference-aspectMask-requiredbitmask)"},
     {"VUID-VkInstanceCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-flags-zerobitmask)"},
     {"VUID-VkInstanceCreateInfo-pApplicationInfo-parameter", "If pApplicationInfo is not NULL, pApplicationInfo must be a valid pointer to a valid VkApplicationInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-pApplicationInfo-parameter)"},
-    {"VUID-VkInstanceCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDebugReportCallbackCreateInfoEXT, VkDebugUtilsMessengerCreateInfoEXT, or VkValidationFlagsEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-pNext-pNext)"},
+    {"VUID-VkInstanceCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDebugReportCallbackCreateInfoEXT, VkDebugUtilsMessengerCreateInfoEXT, VkValidationFeaturesEXT, or VkValidationFlagsEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-pNext-pNext)"},
     {"VUID-VkInstanceCreateInfo-ppEnabledExtensionNames-parameter", "If enabledExtensionCount is not 0, ppEnabledExtensionNames must be a valid pointer to an array of enabledExtensionCount null-terminated UTF-8 strings (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-ppEnabledExtensionNames-parameter)"},
     {"VUID-VkInstanceCreateInfo-ppEnabledLayerNames-parameter", "If enabledLayerCount is not 0, ppEnabledLayerNames must be a valid pointer to an array of enabledLayerCount null-terminated UTF-8 strings (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-ppEnabledLayerNames-parameter)"},
     {"VUID-VkInstanceCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkInstanceCreateInfo-sType-sType)"},
@@ -1290,23 +1392,30 @@
     {"VUID-VkMemoryAllocateFlagsInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateFlagsInfo-sType-sType)"},
     {"VUID-VkMemoryAllocateInfo-None-00643", "If the parameters define an import operation and the external handle specified was created by the Vulkan API, the device mask specified by VkMemoryAllocateFlagsInfo must match that specified when the memory object being imported was allocated. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-None-00643)"},
     {"VUID-VkMemoryAllocateInfo-None-00644", "If the parameters define an import operation and the external handle specified was created by the Vulkan API, the list of physical devices that comprise the logical device passed to vkAllocateMemory must match the list of physical devices that comprise the logical device on which the memory was originally allocated. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-None-00644)"},
-    {"VUID-VkMemoryAllocateInfo-None-01873", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-None-01873)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-00638", "allocationSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-00638)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-00646", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, or VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, allocationSize must match the size reported in the memory requirements of the image or buffer member of the instance of VkDedicatedAllocationMemoryAllocateInfoNV included in the pNext chain. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-00646)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-00647", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, allocationSize must match the size specified when creating the Direct3D 12 heap from which the external handle was extracted. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-00647)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-01742", "If the parameters define an import operation, the external handle specified was created by the Vulkan API, and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR, then the values of allocationSize and memoryTypeIndex must match those specified when the memory object being imported was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-01742)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-01743", "If the parameters define an import operation, the external handle was created by the Vulkan API, and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR or VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, then the values of allocationSize and memoryTypeIndex must match those specified when the memory object being imported was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-01743)"},
     {"VUID-VkMemoryAllocateInfo-allocationSize-01745", "If the parameters define an import operation and the external handle is a host pointer, allocationSize must be an integer multiple of VkPhysicalDeviceExternalMemoryHostPropertiesEXT::minImportedHostPointerAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-01745)"},
+    {"VUID-VkMemoryAllocateInfo-allocationSize-02383", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, allocationSize must be the size returned by vkGetAndroidHardwareBufferPropertiesANDROID for the Android hardware buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-allocationSize-02383)"},
     {"VUID-VkMemoryAllocateInfo-memoryTypeIndex-00645", "If the parameters define an import operation and the external handle is an NT handle or a global share handle created outside of the Vulkan API, the value of memoryTypeIndex must be one of those returned by vkGetMemoryWin32HandlePropertiesKHR. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-memoryTypeIndex-00645)"},
     {"VUID-VkMemoryAllocateInfo-memoryTypeIndex-00648", "If the parameters define an import operation and the external handle is a POSIX file descriptor created outside of the Vulkan API, the value of memoryTypeIndex must be one of those returned by vkGetMemoryFdPropertiesKHR. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-memoryTypeIndex-00648)"},
     {"VUID-VkMemoryAllocateInfo-memoryTypeIndex-01744", "If the parameters define an import operation and the external handle is a host pointer, the value of memoryTypeIndex must be one of those returned by vkGetMemoryHostPointerPropertiesEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-memoryTypeIndex-01744)"},
     {"VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872", "If the protected memory feature is not enabled, the VkMemoryAllocateInfo::memoryTypeIndex must not indicate a memory type that reports VK_MEMORY_PROPERTY_PROTECTED_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872)"},
+    {"VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, memoryTypeIndex must be one of those returned by vkGetAndroidHardwareBufferPropertiesANDROID for the Android hardware buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385)"},
     {"VUID-VkMemoryAllocateInfo-pNext-00639", "If the pNext chain contains an instance of     VkExportMemoryAllocateInfo, and any of the handle types specified     in VkExportMemoryAllocateInfo::handleTypes require a     dedicated allocation, as reported by     vkGetPhysicalDeviceImageFormatProperties2 in     VkExternalImageFormatProperties::externalMemoryProperties::externalMemoryFeatures     or     VkExternalBufferProperties::externalMemoryProperties::externalMemoryFeatures,     the pNext chain must contain an instance of ifdef::VK_KHR_dedicated_allocation[VkMemoryDedicatedAllocateInfo] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-00639)"},
     {"VUID-VkMemoryAllocateInfo-pNext-00640", "If the pNext chain contains an instance of VkExportMemoryAllocateInfo, it must not contain an instance of VkExportMemoryAllocateInfoNV or VkExportMemoryWin32HandleInfoNV. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-00640)"},
     {"VUID-VkMemoryAllocateInfo-pNext-00641", "If the pNext chain contains an instance of VkImportMemoryWin32HandleInfoKHR, it must not contain an instance of VkImportMemoryWin32HandleInfoNV. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-00641)"},
     {"VUID-VkMemoryAllocateInfo-pNext-01874", "If the parameters do not define an import operation, and the pNext chain contains an instance of VkExportMemoryAllocateInfo with VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID included in its handleTypes member, and the pNext contains an instance of VkMemoryDedicatedAllocateInfo with image not equal to VK_NULL_HANDLE, then allocationSize must be 0, otherwise allocationSize must be greater than 0. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-01874)"},
-    {"VUID-VkMemoryAllocateInfo-pNext-01875", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-01875)"},
-    {"VUID-VkMemoryAllocateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDedicatedAllocationMemoryAllocateInfoNV, VkExportMemoryAllocateInfo, VkExportMemoryAllocateInfoNV, VkExportMemoryWin32HandleInfoKHR, VkExportMemoryWin32HandleInfoNV, VkImportAndroidHardwareBufferInfoANDROID, VkImportMemoryFdInfoKHR, VkImportMemoryHostPointerInfoEXT, VkImportMemoryWin32HandleInfoKHR, VkImportMemoryWin32HandleInfoNV, VkMemoryAllocateFlagsInfo, or VkMemoryDedicatedAllocateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-pNext)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02384", "If the parameters define an import operation and the external handle type is VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, and the pNext chain does not contain an instance of VkMemoryDedicatedAllocateInfo or VkMemoryDedicatedAllocateInfo::image is VK_NULL_HANDLE, the Android hardware buffer must have a AHardwareBuffer_Desc::format of AHARDWAREBUFFER_FORMAT_BLOB and a AHardwareBuffer_Desc::usage that includes AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02384)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02386", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, the Android hardware buffer's AHardwareBuffer::usage must include at least one of AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT or AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02386)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02387", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, the format of image must be VK_FORMAT_UNDEFINED or the format returned by vkGetAndroidHardwareBufferPropertiesANDROID in VkAndroidHardwareBufferFormatPropertiesANDROID::format for the Android hardware buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02387)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02388", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, the width, height, and array layer dimensions of image and the Android hardware buffer's AHardwareBuffer_Desc must be identical. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02388)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02389", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, and the Android hardware buffer's AHardwareBuffer::usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, the image must have a complete mipmap chain. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02389)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02390", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, each bit set in the usage of image must be listed in AHardwareBuffer Usage Equivalence, and if there is a corresponding AHARDWAREBUFFER_USAGE bit listed that bit must be included in the Android hardware buffer's AHardwareBuffer_Desc::usage. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02390)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-02586", "If the parameters define an import operation, the external handle is an Android hardware buffer, and the pNext chain includes an instance of VkMemoryDedicatedAllocateInfo with image that is not VK_NULL_HANDLE, and the Android hardware buffer's AHardwareBuffer::usage does not include AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, the image must have exactly one mipmap level. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-02586)"},
+    {"VUID-VkMemoryAllocateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDedicatedAllocationMemoryAllocateInfoNV, VkExportMemoryAllocateInfo, VkExportMemoryAllocateInfoNV, VkExportMemoryWin32HandleInfoKHR, VkExportMemoryWin32HandleInfoNV, VkImportAndroidHardwareBufferInfoANDROID, VkImportMemoryFdInfoKHR, VkImportMemoryHostPointerInfoEXT, VkImportMemoryWin32HandleInfoKHR, VkImportMemoryWin32HandleInfoNV, VkMemoryAllocateFlagsInfo, VkMemoryDedicatedAllocateInfo, or VkMemoryPriorityAllocateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-pNext-pNext)"},
     {"VUID-VkMemoryAllocateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-sType-sType)"},
     {"VUID-VkMemoryAllocateInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryAllocateInfo-sType-unique)"},
     {"VUID-VkMemoryBarrier-dstAccessMask-parameter", "dstAccessMask must be a valid combination of VkAccessFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryBarrier-dstAccessMask-parameter)"},
@@ -1328,8 +1437,13 @@
     {"VUID-VkMemoryDedicatedAllocateInfo-image-parameter", "If image is not VK_NULL_HANDLE, image must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryDedicatedAllocateInfo-image-parameter)"},
     {"VUID-VkMemoryDedicatedAllocateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryDedicatedAllocateInfo-sType-sType)"},
     {"VUID-VkMemoryDedicatedRequirements-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryDedicatedRequirements-sType-sType)"},
+    {"VUID-VkMemoryFdPropertiesKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryFdPropertiesKHR-pNext-pNext)"},
+    {"VUID-VkMemoryFdPropertiesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryFdPropertiesKHR-sType-sType)"},
     {"VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882", "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must have been included in VkExportMemoryAllocateInfoKHR::handleTypes when memory was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882)"},
+    {"VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-memory-parameter", "memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-memory-parameter)"},
     {"VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883", "If the pNext chain of the VkMemoryAllocateInfo used to allocate memory included a VkMemoryDedicatedAllocateInfo with non-NULL image member, then that image must already be bound to memory. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883)"},
+    {"VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-pNext)"},
+    {"VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-sType-sType)"},
     {"VUID-VkMemoryGetFdInfoKHR-handleType-00671", "handleType must have been included in VkExportMemoryAllocateInfo::handleTypes when memory was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetFdInfoKHR-handleType-00671)"},
     {"VUID-VkMemoryGetFdInfoKHR-handleType-00672", "handleType must be defined as a POSIX file descriptor handle. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetFdInfoKHR-handleType-00672)"},
     {"VUID-VkMemoryGetFdInfoKHR-handleType-parameter", "handleType must be a valid VkExternalMemoryHandleTypeFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetFdInfoKHR-handleType-parameter)"},
@@ -1345,13 +1459,15 @@
     {"VUID-VkMemoryGetWin32HandleInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryGetWin32HandleInfoKHR-sType-sType)"},
     {"VUID-VkMemoryHostPointerPropertiesEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryHostPointerPropertiesEXT-pNext-pNext)"},
     {"VUID-VkMemoryHostPointerPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryHostPointerPropertiesEXT-sType-sType)"},
+    {"VUID-VkMemoryPriorityAllocateInfoEXT-priority-02602", "priority must be between 0 and 1, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryPriorityAllocateInfoEXT-priority-02602)"},
+    {"VUID-VkMemoryPriorityAllocateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryPriorityAllocateInfoEXT-sType-sType)"},
     {"VUID-VkMemoryRequirements2-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkMemoryDedicatedRequirements (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryRequirements2-pNext-pNext)"},
     {"VUID-VkMemoryRequirements2-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryRequirements2-sType-sType)"},
-    {"VUID-VkMirSurfaceCreateInfoKHR-connection-01263", "connection must point to a valid MirConnection. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMirSurfaceCreateInfoKHR-connection-01263)"},
-    {"VUID-VkMirSurfaceCreateInfoKHR-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMirSurfaceCreateInfoKHR-flags-zerobitmask)"},
-    {"VUID-VkMirSurfaceCreateInfoKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMirSurfaceCreateInfoKHR-pNext-pNext)"},
-    {"VUID-VkMirSurfaceCreateInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMirSurfaceCreateInfoKHR-sType-sType)"},
-    {"VUID-VkMirSurfaceCreateInfoKHR-surface-01264", "surface must point to a valid MirSurface. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMirSurfaceCreateInfoKHR-surface-01264)"},
+    {"VUID-VkMemoryWin32HandlePropertiesKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryWin32HandlePropertiesKHR-pNext-pNext)"},
+    {"VUID-VkMemoryWin32HandlePropertiesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMemoryWin32HandlePropertiesKHR-sType-sType)"},
+    {"VUID-VkMetalSurfaceCreateInfoEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMetalSurfaceCreateInfoEXT-flags-zerobitmask)"},
+    {"VUID-VkMetalSurfaceCreateInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMetalSurfaceCreateInfoEXT-pNext-pNext)"},
+    {"VUID-VkMetalSurfaceCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMetalSurfaceCreateInfoEXT-sType-sType)"},
     {"VUID-VkMultisamplePropertiesEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMultisamplePropertiesEXT-pNext-pNext)"},
     {"VUID-VkMultisamplePropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkMultisamplePropertiesEXT-sType-sType)"},
     {"VUID-VkObjectTableCreateInfoNVX-computeBindingPointSupport-01355", "If the VkDeviceGeneratedCommandsFeaturesNVX::computeBindingPointSupport feature is not enabled, pObjectEntryUsageFlags must not contain VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkObjectTableCreateInfoNVX-computeBindingPointSupport-01355)"},
@@ -1406,10 +1522,16 @@
     {"VUID-VkPhysicalDeviceASTCDecodeFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceASTCDecodeFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceBufferAddressFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceBufferAddressFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceComputeShaderDerivativesFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceComputeShaderDerivativesFeaturesNV-sType-sType)"},
     {"VUID-VkPhysicalDeviceConditionalRenderingFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceConditionalRenderingFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceConservativeRasterizationPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceConservativeRasterizationPropertiesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceCooperativeMatrixFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceCooperativeMatrixFeaturesNV-sType-sType)"},
+    {"VUID-VkPhysicalDeviceCooperativeMatrixPropertiesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceCooperativeMatrixPropertiesNV-sType-sType)"},
     {"VUID-VkPhysicalDeviceCornerSampledImageFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceCornerSampledImageFeaturesNV-sType-sType)"},
+    {"VUID-VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV-sType-sType)"},
+    {"VUID-VkPhysicalDeviceDepthClipEnableFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDepthClipEnableFeaturesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceDepthStencilResolvePropertiesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDepthStencilResolvePropertiesKHR-sType-sType)"},
     {"VUID-VkPhysicalDeviceDescriptorIndexingFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDescriptorIndexingFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceDescriptorIndexingPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDescriptorIndexingPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceDiscardRectanglePropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceDiscardRectanglePropertiesEXT-sType-sType)"},
@@ -1431,7 +1553,13 @@
     {"VUID-VkPhysicalDeviceExternalSemaphoreInfo-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceExternalSemaphoreInfo-pNext-pNext)"},
     {"VUID-VkPhysicalDeviceExternalSemaphoreInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceExternalSemaphoreInfo-sType-sType)"},
     {"VUID-VkPhysicalDeviceFeatures2-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFeatures2-sType-sType)"},
+    {"VUID-VkPhysicalDeviceFloat16Int8FeaturesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFloat16Int8FeaturesKHR-sType-sType)"},
+    {"VUID-VkPhysicalDeviceFloatControlsPropertiesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFloatControlsPropertiesKHR-sType-sType)"},
+    {"VUID-VkPhysicalDeviceFragmentDensityMapFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFragmentDensityMapFeaturesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceFragmentDensityMapPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFragmentDensityMapPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV-sType-sType)"},
+    {"VUID-VkPhysicalDeviceGroupProperties-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceGroupProperties-pNext-pNext)"},
+    {"VUID-VkPhysicalDeviceGroupProperties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceGroupProperties-sType-sType)"},
     {"VUID-VkPhysicalDeviceIDProperties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceIDProperties-sType-sType)"},
     {"VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sharingMode-02314", "If sharingMode is VK_SHARING_MODE_CONCURRENT, then pQueueFamilyIndices must be a valid pointer to an array of queueFamilyIndexCount uint32_t values. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sharingMode-02314)"},
@@ -1440,7 +1568,7 @@
     {"VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sharingMode-parameter", "sharingMode must be a valid VkSharingMode value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageDrmFormatModifierInfoEXT-sharingMode-parameter)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-flags-parameter", "flags must be a valid combination of VkImageCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-flags-parameter)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter", "format must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter)"},
-    {"VUID-VkPhysicalDeviceImageFormatInfo2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkImageFormatListCreateInfoKHR, VkPhysicalDeviceExternalImageFormatInfo, or VkPhysicalDeviceImageDrmFormatModifierInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-pNext-pNext)"},
+    {"VUID-VkPhysicalDeviceImageFormatInfo2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkImageFormatListCreateInfoKHR, VkImageStencilUsageCreateInfoEXT, VkPhysicalDeviceExternalImageFormatInfo, VkPhysicalDeviceImageDrmFormatModifierInfoEXT, or VkPhysicalDeviceImageViewImageFormatInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-pNext-pNext)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-sType-sType)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-sType-unique)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249", "tiling must be VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT if and only if the pNext chain contains VkPhysicalDeviceImageDrmFormatModifierInfoEXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249)"},
@@ -1449,10 +1577,14 @@
     {"VUID-VkPhysicalDeviceImageFormatInfo2-type-parameter", "type must be a valid VkImageType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-type-parameter)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter", "usage must be a valid combination of VkImageUsageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter)"},
     {"VUID-VkPhysicalDeviceImageFormatInfo2-usage-requiredbitmask", "usage must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageFormatInfo2-usage-requiredbitmask)"},
+    {"VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter", "imageViewType must be a valid VkImageViewType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter)"},
+    {"VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceInlineUniformBlockFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceInlineUniformBlockFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceInlineUniformBlockPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceInlineUniformBlockPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceMaintenance3Properties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMaintenance3Properties-sType-sType)"},
-    {"VUID-VkPhysicalDeviceMemoryProperties2-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMemoryProperties2-pNext-pNext)"},
+    {"VUID-VkPhysicalDeviceMemoryBudgetPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMemoryBudgetPropertiesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceMemoryPriorityFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMemoryPriorityFeaturesEXT-sType-sType)"},
+    {"VUID-VkPhysicalDeviceMemoryProperties2-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkPhysicalDeviceMemoryBudgetPropertiesEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMemoryProperties2-pNext-pNext)"},
     {"VUID-VkPhysicalDeviceMemoryProperties2-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMemoryProperties2-sType-sType)"},
     {"VUID-VkPhysicalDeviceMeshShaderFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMeshShaderFeaturesNV-sType-sType)"},
     {"VUID-VkPhysicalDeviceMeshShaderPropertiesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMeshShaderPropertiesNV-sType-sType)"},
@@ -1463,17 +1595,18 @@
     {"VUID-VkPhysicalDeviceMultiviewProperties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceMultiviewProperties-sType-sType)"},
     {"VUID-VkPhysicalDevicePCIBusInfoPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDevicePCIBusInfoPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDevicePointClippingProperties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDevicePointClippingProperties-sType-sType)"},
-    {"VUID-VkPhysicalDeviceProperties2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT, VkPhysicalDeviceConservativeRasterizationPropertiesEXT, VkPhysicalDeviceDescriptorIndexingPropertiesEXT, VkPhysicalDeviceDiscardRectanglePropertiesEXT, VkPhysicalDeviceDriverPropertiesKHR, VkPhysicalDeviceExternalMemoryHostPropertiesEXT, VkPhysicalDeviceIDProperties, VkPhysicalDeviceInlineUniformBlockPropertiesEXT, VkPhysicalDeviceMaintenance3Properties, VkPhysicalDeviceMeshShaderPropertiesNV, VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX, VkPhysicalDeviceMultiviewProperties, VkPhysicalDevicePCIBusInfoPropertiesEXT, VkPhysicalDevicePointClippingProperties, VkPhysicalDeviceProtectedMemoryProperties, VkPhysicalDevicePushDescriptorPropertiesKHR, VkPhysicalDeviceRaytracingPropertiesNVX, VkPhysicalDeviceSampleLocationsPropertiesEXT, VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT, VkPhysicalDeviceShaderCorePropertiesAMD, VkPhysicalDeviceSubgroupProperties, VkPhysicalDeviceTransformFeedbackPropertiesEXT, or VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProperties2-pNext-pNext)"},
+    {"VUID-VkPhysicalDeviceProperties2-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT, VkPhysicalDeviceConservativeRasterizationPropertiesEXT, VkPhysicalDeviceCooperativeMatrixPropertiesNV, VkPhysicalDeviceDepthStencilResolvePropertiesKHR, VkPhysicalDeviceDescriptorIndexingPropertiesEXT, VkPhysicalDeviceDiscardRectanglePropertiesEXT, VkPhysicalDeviceDriverPropertiesKHR, VkPhysicalDeviceExternalMemoryHostPropertiesEXT, VkPhysicalDeviceFloatControlsPropertiesKHR, VkPhysicalDeviceFragmentDensityMapPropertiesEXT, VkPhysicalDeviceIDProperties, VkPhysicalDeviceInlineUniformBlockPropertiesEXT, VkPhysicalDeviceMaintenance3Properties, VkPhysicalDeviceMeshShaderPropertiesNV, VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX, VkPhysicalDeviceMultiviewProperties, VkPhysicalDevicePCIBusInfoPropertiesEXT, VkPhysicalDevicePointClippingProperties, VkPhysicalDeviceProtectedMemoryProperties, VkPhysicalDevicePushDescriptorPropertiesKHR, VkPhysicalDeviceRayTracingPropertiesNV, VkPhysicalDeviceSampleLocationsPropertiesEXT, VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT, VkPhysicalDeviceShaderCorePropertiesAMD, VkPhysicalDeviceShadingRateImagePropertiesNV, VkPhysicalDeviceSubgroupProperties, VkPhysicalDeviceTransformFeedbackPropertiesEXT, or VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProperties2-pNext-pNext)"},
     {"VUID-VkPhysicalDeviceProperties2-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProperties2-sType-sType)"},
     {"VUID-VkPhysicalDeviceProperties2-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProperties2-sType-unique)"},
     {"VUID-VkPhysicalDeviceProtectedMemoryFeatures-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProtectedMemoryFeatures-sType-sType)"},
     {"VUID-VkPhysicalDeviceProtectedMemoryProperties-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceProtectedMemoryProperties-sType-sType)"},
     {"VUID-VkPhysicalDevicePushDescriptorPropertiesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDevicePushDescriptorPropertiesKHR-sType-sType)"},
-    {"VUID-VkPhysicalDeviceRaytracingPropertiesNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceRaytracingPropertiesNVX-sType-sType)"},
+    {"VUID-VkPhysicalDeviceRayTracingPropertiesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceRayTracingPropertiesNV-sType-sType)"},
     {"VUID-VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV-sType-sType)"},
     {"VUID-VkPhysicalDeviceSampleLocationsPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceSampleLocationsPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceSamplerYcbcrConversionFeatures-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceSamplerYcbcrConversionFeatures-sType-sType)"},
+    {"VUID-VkPhysicalDeviceScalarBlockLayoutFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceScalarBlockLayoutFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceShaderAtomicInt64FeaturesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceShaderAtomicInt64FeaturesKHR-sType-sType)"},
     {"VUID-VkPhysicalDeviceShaderCorePropertiesAMD-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceShaderCorePropertiesAMD-sType-sType)"},
     {"VUID-VkPhysicalDeviceShaderDrawParameterFeatures-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceShaderDrawParameterFeatures-sType-sType)"},
@@ -1500,6 +1633,7 @@
     {"VUID-VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT-sType-sType)"},
     {"VUID-VkPhysicalDeviceVulkanMemoryModelFeaturesKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceVulkanMemoryModelFeaturesKHR-sType-sType)"},
+    {"VUID-VkPhysicalDeviceYcbcrImageArraysFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPhysicalDeviceYcbcrImageArraysFeaturesEXT-sType-sType)"},
     {"VUID-VkPipelineCacheCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCacheCreateInfo-flags-zerobitmask)"},
     {"VUID-VkPipelineCacheCreateInfo-initialDataSize-00768", "If initialDataSize is not 0, it must be equal to the size of pInitialData, as returned by vkGetPipelineCacheData when pInitialData was originally retrieved (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCacheCreateInfo-initialDataSize-00768)"},
     {"VUID-VkPipelineCacheCreateInfo-initialDataSize-00769", "If initialDataSize is not 0, pInitialData must have been retrieved from a previous call to vkGetPipelineCacheData (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCacheCreateInfo-initialDataSize-00769)"},
@@ -1535,7 +1669,6 @@
     {"VUID-VkPipelineColorBlendStateCreateInfo-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkPipelineColorBlendAdvancedStateCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineColorBlendStateCreateInfo-pNext-pNext)"},
     {"VUID-VkPipelineColorBlendStateCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineColorBlendStateCreateInfo-sType-sType)"},
     {"VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationMode-parameter", "coverageModulationMode must be a valid VkCoverageModulationModeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationMode-parameter)"},
-    {"VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableCount-arraylength", "coverageModulationTableCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableCount-arraylength)"},
     {"VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405", "If coverageModulationTableEnable is VK_TRUE, coverageModulationTableCount must be equal to the number of rasterization samples divided by the number of color samples in the subpass. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405)"},
     {"VUID-VkPipelineCoverageModulationStateCreateInfoNV-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCoverageModulationStateCreateInfoNV-flags-zerobitmask)"},
     {"VUID-VkPipelineCoverageModulationStateCreateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineCoverageModulationStateCreateInfoNV-sType-sType)"},
@@ -1571,6 +1704,7 @@
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-02215", "The total number of bindings with a descriptorType of VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT accessible to any given shader stage across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceInlineUniformBlockPropertiesEXT::maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-02215)"},
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-02216", "The total number of bindings in descriptor set layouts created without the VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT bit set with a descriptorType of VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT accessible across all shader stages and across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceInlineUniformBlockPropertiesEXT::maxDescriptorSetInlineUniformBlocks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-02216)"},
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-02217", "The total number of bindings with a descriptorType of VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT accessible across all shader stages and across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceInlineUniformBlockPropertiesEXT::maxDescriptorSetUpdateAfterBindInlineUniformBlocks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-02217)"},
+    {"VUID-VkPipelineLayoutCreateInfo-descriptorType-02381", "The total number of bindings with a descriptorType of VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV accessible across all shader stages and across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxDescriptorSetAccelerationStructures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-02381)"},
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-03016", "The total number of descriptors in descriptor set layouts created without the VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT bit set with a descriptorType of VK_DESCRIPTOR_TYPE_SAMPLER and VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER accessible to any given shader stage across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceLimits::maxPerStageDescriptorSamplers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-03016)"},
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-03017", "The total number of descriptors in descriptor set layouts created without the VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT bit set with a descriptorType of VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER and VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC accessible to any given shader stage across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceLimits::maxPerStageDescriptorUniformBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-03017)"},
     {"VUID-VkPipelineLayoutCreateInfo-descriptorType-03018", "The total number of descriptors in descriptor set layouts created without the VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT bit set with a descriptorType of VK_DESCRIPTOR_TYPE_STORAGE_BUFFER and VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC accessible to any given shader stage across all elements of pSetLayouts must be less than or equal to VkPhysicalDeviceLimits::maxPerStageDescriptorStorageBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineLayoutCreateInfo-descriptorType-03018)"},
@@ -1626,7 +1760,7 @@
     {"VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786", "minSampleShading must be in the range [0,1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786)"},
     {"VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPipelineCoverageModulationStateCreateInfoNV, VkPipelineCoverageToColorStateCreateInfoNV, or VkPipelineSampleLocationsStateCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext)"},
     {"VUID-VkPipelineMultisampleStateCreateInfo-pSampleMask-parameter", "If pSampleMask is not NULL, pSampleMask must be a valid pointer to an array of (rasterizationSamples/32) VkSampleMask values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-pSampleMask-parameter)"},
-    {"VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415", "If the subpass has any color attachments and rasterizationSamples is greater than the number of color samples, then sampleShadingEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415)"},
+    {"VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415", "If the VK_NV_framebuffer_mixed_samples extension is enabled, and if the subpass has any color attachments and rasterizationSamples is greater than the number of color samples, then sampleShadingEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415)"},
     {"VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter", "rasterizationSamples must be a valid VkSampleCountFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter)"},
     {"VUID-VkPipelineMultisampleStateCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-sType-sType)"},
     {"VUID-VkPipelineMultisampleStateCreateInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineMultisampleStateCreateInfo-sType-unique)"},
@@ -1635,11 +1769,13 @@
     {"VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-extraPrimitiveOverestimationSize-01769", "extraPrimitiveOverestimationSize must be in the range of 0.0 to VkPhysicalDeviceConservativeRasterizationPropertiesEXT::maxExtraPrimitiveOverestimationSize inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-extraPrimitiveOverestimationSize-01769)"},
     {"VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-flags-zerobitmask)"},
     {"VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-sType-sType)"},
+    {"VUID-VkPipelineRasterizationDepthClipStateCreateInfoEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationDepthClipStateCreateInfoEXT-flags-zerobitmask)"},
+    {"VUID-VkPipelineRasterizationDepthClipStateCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationDepthClipStateCreateInfoEXT-sType-sType)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter", "cullMode must be a valid combination of VkCullModeFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782", "If the depth clamping feature is not enabled, depthClampEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-flags-zerobitmask)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter", "frontFace must be a valid VkFrontFace value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter)"},
-    {"VUID-VkPipelineRasterizationStateCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPipelineRasterizationConservativeStateCreateInfoEXT, VkPipelineRasterizationStateRasterizationOrderAMD, or VkPipelineRasterizationStateStreamCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-pNext-pNext)"},
+    {"VUID-VkPipelineRasterizationStateCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkPipelineRasterizationConservativeStateCreateInfoEXT, VkPipelineRasterizationDepthClipStateCreateInfoEXT, VkPipelineRasterizationStateRasterizationOrderAMD, or VkPipelineRasterizationStateStreamCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-pNext-pNext)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01413", "If the non-solid fill modes feature is not enabled, polygonMode must be VK_POLYGON_MODE_FILL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01413)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01414", "If the VK_NV_fill_rectangle extension is not enabled, polygonMode must not be VK_POLYGON_MODE_FILL_RECTANGLE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01414)"},
     {"VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507", "If the non-solid fill modes feature is not enabled, polygonMode must be VK_POLYGON_MODE_FILL or VK_POLYGON_MODE_FILL_RECTANGLE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507)"},
@@ -1674,8 +1810,6 @@
     {"VUID-VkPipelineShaderStageCreateInfo-stage-00713", "If stage is VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT or VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, and the identified entry point has an OpExecutionMode instruction that specifies a patch size with OutputVertices, the patch size must be greater than 0 and less than or equal to VkPhysicalDeviceLimits::maxTessellationPatchSize (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00713)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-00714", "If stage is VK_SHADER_STAGE_GEOMETRY_BIT, the identified entry point must have an OpExecutionMode instruction that specifies a maximum output vertex count that is greater than 0 and less than or equal to VkPhysicalDeviceLimits::maxGeometryOutputVertices (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00714)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-00715", "If stage is VK_SHADER_STAGE_GEOMETRY_BIT, the identified entry point must have an OpExecutionMode instruction that specifies an invocation count that is greater than 0 and less than or equal to VkPhysicalDeviceLimits::maxGeometryShaderInvocations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00715)"},
-    {"VUID-VkPipelineShaderStageCreateInfo-stage-00716", "If stage is VK_SHADER_STAGE_GEOMETRY_BIT, and the identified entry point writes to Layer for any primitive, it must write the same value to Layer for all vertices of a given primitive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00716)"},
-    {"VUID-VkPipelineShaderStageCreateInfo-stage-00717", "If stage is VK_SHADER_STAGE_GEOMETRY_BIT, and the identified entry point writes to ViewportIndex for any primitive, it must write the same value to ViewportIndex for all vertices of a given primitive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00717)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-00718", "If stage is VK_SHADER_STAGE_FRAGMENT_BIT, the identified entry point must not include any output variables in its interface decorated with CullDistance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00718)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-00719", "If stage is VK_SHADER_STAGE_FRAGMENT_BIT, and the identified entry point writes to FragDepth in any execution path, it must write to FragDepth in all execution paths (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-00719)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-01511", "If stage is VK_SHADER_STAGE_FRAGMENT_BIT, and the identified entry point writes to FragStencilRefEXT in any execution path, it must write to FragStencilRefEXT in all execution paths (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-01511)"},
@@ -1683,6 +1817,8 @@
     {"VUID-VkPipelineShaderStageCreateInfo-stage-02092", "If the task shader feature is not enabled, stage must not be VK_SHADER_STAGE_TASK_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-02092)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-02093", "If stage is VK_SHADER_STAGE_MESH_BIT_NV, the identified entry point must have an OpExecutionMode instruction that specifies a maximum output vertex count, OutputVertices, that is greater than 0 and less than or equal to VkPhysicalDeviceMeshShaderPropertiesNV::maxMeshOutputVertices. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-02093)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-02094", "If stage is VK_SHADER_STAGE_MESH_BIT_NV, the identified entry point must have an OpExecutionMode instruction that specifies a maximum output primitive count, OutputPrimitivesNV, that is greater than 0 and less than or equal to VkPhysicalDeviceMeshShaderPropertiesNV::maxMeshOutputPrimitives. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-02094)"},
+    {"VUID-VkPipelineShaderStageCreateInfo-stage-02596", "If stage is a vertex processing stage, and the identified entry point writes to Layer for any primitive, it must write the same value to Layer for all vertices of a given primitive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-02596)"},
+    {"VUID-VkPipelineShaderStageCreateInfo-stage-02597", "If stage is a vertex processing stage, and the identified entry point writes to ViewportIndex for any primitive, it must write the same value to ViewportIndex for all vertices of a given primitive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-02597)"},
     {"VUID-VkPipelineShaderStageCreateInfo-stage-parameter", "stage must be a valid VkShaderStageFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-stage-parameter)"},
     {"VUID-VkPipelineTessellationDomainOriginStateCreateInfo-domainOrigin-parameter", "domainOrigin must be a valid VkTessellationDomainOrigin value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineTessellationDomainOriginStateCreateInfo-domainOrigin-parameter)"},
     {"VUID-VkPipelineTessellationDomainOriginStateCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineTessellationDomainOriginStateCreateInfo-sType-sType)"},
@@ -1733,6 +1869,7 @@
     {"VUID-VkPipelineViewportStateCreateInfo-viewportCount-arraylength", "viewportCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportStateCreateInfo-viewportCount-arraylength)"},
     {"VUID-VkPipelineViewportStateCreateInfo-viewportWScalingEnable-01726", "If the viewportWScalingEnable member of a VkPipelineViewportWScalingStateCreateInfoNV structure chained to the pNext chain is VK_TRUE, the viewportCount member of the VkPipelineViewportWScalingStateCreateInfoNV structure must be equal to viewportCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportStateCreateInfo-viewportWScalingEnable-01726)"},
     {"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportSwizzleStateCreateInfoNV-flags-zerobitmask)"},
+    {"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-pViewportSwizzles-parameter", "pViewportSwizzles must be a valid pointer to an array of viewportCount valid VkViewportSwizzleNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportSwizzleStateCreateInfoNV-pViewportSwizzles-parameter)"},
     {"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportSwizzleStateCreateInfoNV-sType-sType)"},
     {"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-01215", "viewportCount must match the viewportCount set in VkPipelineViewportStateCreateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-01215)"},
     {"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-arraylength", "viewportCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-arraylength)"},
@@ -1752,7 +1889,7 @@
     {"VUID-VkPresentRegionKHR-pRectangles-parameter", "If rectangleCount is not 0, and pRectangles is not NULL, pRectangles must be a valid pointer to an array of rectangleCount valid VkRectLayerKHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionKHR-pRectangles-parameter)"},
     {"VUID-VkPresentRegionsKHR-pRegions-parameter", "If pRegions is not NULL, pRegions must be a valid pointer to an array of swapchainCount valid VkPresentRegionKHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionsKHR-pRegions-parameter)"},
     {"VUID-VkPresentRegionsKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionsKHR-sType-sType)"},
-    {"VUID-VkPresentRegionsKHR-swapchainCount-01260", "swapchainCount must be the same value as VkPresentInfoKHR::swapchainCount, where VkPresentInfoKHR is in the pNext-chain of this VkPresentRegionsKHR structure. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionsKHR-swapchainCount-01260)"},
+    {"VUID-VkPresentRegionsKHR-swapchainCount-01260", "swapchainCount must be the same value as VkPresentInfoKHR::swapchainCount, where VkPresentInfoKHR is in the pNext chain of this VkPresentRegionsKHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionsKHR-swapchainCount-01260)"},
     {"VUID-VkPresentRegionsKHR-swapchainCount-arraylength", "swapchainCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentRegionsKHR-swapchainCount-arraylength)"},
     {"VUID-VkPresentTimesInfoGOOGLE-pTimes-parameter", "If pTimes is not NULL, pTimes must be a valid pointer to an array of swapchainCount VkPresentTimeGOOGLE structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentTimesInfoGOOGLE-pTimes-parameter)"},
     {"VUID-VkPresentTimesInfoGOOGLE-sType-sType", "sType must be VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPresentTimesInfoGOOGLE-sType-sType)"},
@@ -1779,54 +1916,78 @@
     {"VUID-VkQueueFamilyCheckpointPropertiesNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkQueueFamilyCheckpointPropertiesNV-sType-sType)"},
     {"VUID-VkQueueFamilyProperties2-pNext-pNext", "pNext must be NULL or a pointer to a valid instance of VkQueueFamilyCheckpointPropertiesNV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkQueueFamilyProperties2-pNext-pNext)"},
     {"VUID-VkQueueFamilyProperties2-sType-sType", "sType must be VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkQueueFamilyProperties2-sType-sType)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-commonparent", "Both of basePipelineHandle, and layout that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-commonparent)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-flags-parameter", "flags must be a valid combination of VkPipelineCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-flags-parameter)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-layout-parameter", "layout must be a valid VkPipelineLayout handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-layout-parameter)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-pGroupNumbers-parameter", "pGroupNumbers must be a valid pointer to an array of stageCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-pGroupNumbers-parameter)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-pNext-pNext)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-pStages-parameter", "pStages must be a valid pointer to an array of stageCount valid VkPipelineShaderStageCreateInfo structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-pStages-parameter)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-sType-sType", "sType must be VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-sType-sType)"},
-    {"VUID-VkRaytracingPipelineCreateInfoNVX-stageCount-arraylength", "stageCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRaytracingPipelineCreateInfoNVX-stageCount-arraylength)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-commonparent", "Both of basePipelineHandle, and layout that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-commonparent)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-flags-02404", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineIndex is -1, basePipelineHandle must be a valid handle to a ray tracing VkPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-flags-02404)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-flags-02405", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineHandle is VK_NULL_HANDLE, basePipelineIndex must be a valid index into the calling command's pCreateInfos parameter (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-flags-02405)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-flags-02406", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineIndex is not -1, basePipelineHandle must be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-flags-02406)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-flags-02407", "If flags contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and basePipelineHandle is not VK_NULL_HANDLE, basePipelineIndex must be -1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-flags-02407)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-flags-parameter", "flags must be a valid combination of VkPipelineCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-flags-parameter)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-groupCount-arraylength", "groupCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-groupCount-arraylength)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-layout-02410", "layout must be consistent with all shaders specified in pStages (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-layout-02410)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-layout-02411", "The number of resources in layout accessible to each shader stage that is used by the pipeline must be less than or equal to VkPhysicalDeviceLimits::maxPerStageResources (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-layout-02411)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-layout-parameter", "layout must be a valid VkPipelineLayout handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-layout-parameter)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-maxRecursionDepth-02412", "maxRecursionDepth must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxRecursionDepth (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-maxRecursionDepth-02412)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-pGroups-parameter", "pGroups must be a valid pointer to an array of groupCount valid VkRayTracingShaderGroupCreateInfoNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-pGroups-parameter)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-pNext-pNext)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-pStages-02409", "The shader code for the entry points identified by pStages, and the rest of the state identified by this structure must adhere to the pipeline linking rules described in the Shader Interfaces chapter (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-pStages-02409)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-pStages-parameter", "pStages must be a valid pointer to an array of stageCount valid VkPipelineShaderStageCreateInfo structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-pStages-parameter)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-sType-sType)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-stage-02408", "The stage member of one element of pStages must be VK_SHADER_STAGE_RAYGEN_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-stage-02408)"},
+    {"VUID-VkRayTracingPipelineCreateInfoNV-stageCount-arraylength", "stageCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingPipelineCreateInfoNV-stageCount-arraylength)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-anyHitShader-02418", "anyHitShader must be either VK_SHADER_UNUSED_NV or a valid index into pStages referring to a shader of VK_SHADER_STAGE_ANY_HIT_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-anyHitShader-02418)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-closestHitShader-02417", "closestHitShader must be either VK_SHADER_UNUSED_NV or a valid index into pStages referring to a shader of VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-closestHitShader-02417)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-pNext-pNext)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-sType-sType)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-type-02413", "If type is VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV then generalShader must be a valid index into pStages referring to a shader of VK_SHADER_STAGE_RAYGEN_BIT_NV, VK_SHADER_STAGE_MISS_BIT_NV, or VK_SHADER_STAGE_CALLABLE_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-type-02413)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-type-02414", "If type is VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV then closestHitShader, anyHitShader, and intersectionShader must be VK_SHADER_UNUSED_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-type-02414)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-type-02415", "If type is VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV then intersectionShader must be a valid index into pStages referring to a shader of VK_SHADER_STAGE_INTERSECTION_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-type-02415)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-type-02416", "If type is VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV then intersectionShader must be VK_SHADER_UNUSED_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-type-02416)"},
+    {"VUID-VkRayTracingShaderGroupCreateInfoNV-type-parameter", "type must be a valid VkRayTracingShaderGroupTypeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRayTracingShaderGroupCreateInfoNV-type-parameter)"},
     {"VUID-VkRectLayerKHR-layer-01262", "layer must be less than imageArrayLayers member of the VkSwapchainCreateInfoKHR structure given to vkCreateSwapchainKHR. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRectLayerKHR-layer-01262)"},
     {"VUID-VkRectLayerKHR-offset-01261", "The sum of offset and extent must be no greater than the imageExtent member of the VkSwapchainCreateInfoKHR structure given to vkCreateSwapchainKHR. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRectLayerKHR-offset-01261)"},
     {"VUID-VkRenderPassBeginInfo-clearValueCount-00902", "clearValueCount must be greater than the largest attachment index in renderPass that specifies a loadOp (or stencilLoadOp, if the attachment has a depth/stencil format) of VK_ATTACHMENT_LOAD_OP_CLEAR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-clearValueCount-00902)"},
-    {"VUID-VkRenderPassBeginInfo-clearValueCount-00903", "If clearValueCount is not 0, pClearValues must be a valid pointer to an array of clearValueCount valid VkClearValue unions (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-clearValueCount-00903)"},
     {"VUID-VkRenderPassBeginInfo-commonparent", "Both of framebuffer, and renderPass must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-commonparent)"},
     {"VUID-VkRenderPassBeginInfo-framebuffer-parameter", "framebuffer must be a valid VkFramebuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-framebuffer-parameter)"},
+    {"VUID-VkRenderPassBeginInfo-pClearValues-parameter", "If clearValueCount is not 0, pClearValues must be a valid pointer to an array of clearValueCount VkClearValue unions (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-pClearValues-parameter)"},
     {"VUID-VkRenderPassBeginInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDeviceGroupRenderPassBeginInfo or VkRenderPassSampleLocationsBeginInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-pNext-pNext)"},
     {"VUID-VkRenderPassBeginInfo-renderPass-00904", "renderPass must be compatible with the renderPass member of the VkFramebufferCreateInfo structure specified when creating framebuffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-renderPass-00904)"},
     {"VUID-VkRenderPassBeginInfo-renderPass-parameter", "renderPass must be a valid VkRenderPass handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-renderPass-parameter)"},
     {"VUID-VkRenderPassBeginInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-sType-sType)"},
     {"VUID-VkRenderPassBeginInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassBeginInfo-sType-unique)"},
-    {"VUID-VkRenderPassCreateInfo-None-00832", "If any two subpasses operate on attachments with overlapping ranges of the same VkDeviceMemory object, and at least one subpass writes to that area of VkDeviceMemory, a subpass dependency must be included (either directly or via some intermediate subpasses) between them (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-None-00832)"},
-    {"VUID-VkRenderPassCreateInfo-attachment-00833", "If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments or pDepthStencilAttachment, or the attachment indexed by any element of pPreserveAttachments in any element of pSubpasses is bound to a range of a VkDeviceMemory object that overlaps with any other attachment in any subpass (including the same subpass), the VkAttachmentDescription structures describing them must include VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT in flags (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00833)"},
     {"VUID-VkRenderPassCreateInfo-attachment-00834", "If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not VK_ATTACHMENT_UNUSED, it must be less than attachmentCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834)"},
-    {"VUID-VkRenderPassCreateInfo-flags-parameter", "flags must be a valid combination of VkRenderPassCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-flags-parameter)"},
+    {"VUID-VkRenderPassCreateInfo-dstSubpass-02518", "The dstSubpass member of each element of pDependencies must be less than subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-dstSubpass-02518)"},
     {"VUID-VkRenderPassCreateInfo-pAttachments-00836", "For any member of pAttachments with a loadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-00836)"},
     {"VUID-VkRenderPassCreateInfo-pAttachments-01566", "For any member of pAttachments with a loadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-01566)"},
     {"VUID-VkRenderPassCreateInfo-pAttachments-01567", "For any member of pAttachments with a stencilLoadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-01567)"},
+    {"VUID-VkRenderPassCreateInfo-pAttachments-02511", "For any member of pAttachments with a stencilLoadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-02511)"},
     {"VUID-VkRenderPassCreateInfo-pAttachments-parameter", "If attachmentCount is not 0, pAttachments must be a valid pointer to an array of attachmentCount valid VkAttachmentDescription structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-parameter)"},
-    {"VUID-VkRenderPassCreateInfo-pDependencies-00837", "For any element of pDependencies, if the srcSubpass is not VK_SUBPASS_EXTERNAL, all stage flags included in the srcStageMask member of that dependency must be a pipeline stage supported by the pipeline identified by the pipelineBindPoint member of the source subpass. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-00837)"},
-    {"VUID-VkRenderPassCreateInfo-pDependencies-00838", "For any element of pDependencies, if the dstSubpass is not VK_SUBPASS_EXTERNAL, all stage flags included in the dstStageMask member of that dependency must be a pipeline stage supported by the pipeline identified by the pipelineBindPoint member of the source subpass. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-00838)"},
+    {"VUID-VkRenderPassCreateInfo-pDependencies-00837", "For any element of pDependencies, if the srcSubpass is not VK_SUBPASS_EXTERNAL, all stage flags included in the srcStageMask member of that dependency must be a pipeline stage supported by the pipeline identified by the pipelineBindPoint member of the source subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-00837)"},
+    {"VUID-VkRenderPassCreateInfo-pDependencies-00838", "For any element of pDependencies, if the dstSubpass is not VK_SUBPASS_EXTERNAL, all stage flags included in the dstStageMask member of that dependency must be a pipeline stage supported by the pipeline identified by the pipelineBindPoint member of the source subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-00838)"},
     {"VUID-VkRenderPassCreateInfo-pDependencies-parameter", "If dependencyCount is not 0, pDependencies must be a valid pointer to an array of dependencyCount valid VkSubpassDependency structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-parameter)"},
     {"VUID-VkRenderPassCreateInfo-pNext-01926", "If the pNext chain includes an instance of VkRenderPassInputAttachmentAspectCreateInfo, the subpass member of each element of its pAspectReferences member must be less than subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01926)"},
     {"VUID-VkRenderPassCreateInfo-pNext-01927", "If the pNext chain includes an instance of VkRenderPassInputAttachmentAspectCreateInfo, the inputAttachmentIndex member of each element of its pAspectReferences member must be less than the value of inputAttachmentCount in the member of pSubpasses identified by its subpass member (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01927)"},
     {"VUID-VkRenderPassCreateInfo-pNext-01928", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, and its subpassCount member is not zero, that member must be equal to the value of subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01928)"},
     {"VUID-VkRenderPassCreateInfo-pNext-01929", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, if its dependencyCount member is not zero, it must be equal to dependencyCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01929)"},
     {"VUID-VkRenderPassCreateInfo-pNext-01930", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, for each non-zero element of pViewOffsets, the srcSubpass and dstSubpass members of pDependencies at the same index must not be equal (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01930)"},
-    {"VUID-VkRenderPassCreateInfo-pNext-01963", "If the pNext chain includes an instance of VkRenderPassInputAttachmentAspectCreateInfo, the aspectMask member of any element of pAspectReferences must only include aspects that are present in images of the format of the input attachment specified by the subpass and inputAttachment of the same element of pAspectReferences (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01963)"},
-    {"VUID-VkRenderPassCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkRenderPassInputAttachmentAspectCreateInfo or VkRenderPassMultiviewCreateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-pNext)"},
-    {"VUID-VkRenderPassCreateInfo-pPreserveAttachments-00835", "The value of each element of the pPreserveAttachments member in each element of pSubpasses must not be VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pPreserveAttachments-00835)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-01963", "If the pNext chain includes an instance of VkRenderPassInputAttachmentAspectCreateInfo, for any element of the pInputAttachments member of any element of pSubpasses where the attachment member is not VK_ATTACHMENT_UNUSED, the aspectMask member of the corresponding element of VkRenderPassInputAttachmentAspectCreateInfo::pAspectReferences must only include aspects that are present in images of the format specified by the element of pAttachments at attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-01963)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-02512", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, for any element of pDependencies with a dependencyFlags member that doesn't include VK_DEPENDENCY_VIEW_LOCAL_BIT, the corresponding element of the pViewOffsets member of that VkRenderPassMultiviewCreateInfo instance must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-02512)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-02513", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, elements of its pViewMasks member must either all be 0, or all not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-02513)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-02514", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, and each element of its pViewMasks member is 0, the dependencyFlags member of each element of pDependencies must not include VK_DEPENDENCY_VIEW_LOCAL_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-02514)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-02515", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, and each element of its pViewMasks member is 0, correlatedViewMaskCount must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-02515)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-02516", "If the pNext chain includes an instance of VkRenderPassMultiviewCreateInfo, each element of its pViewMask member must not include a bit at a position greater than the value of VkPhysicalDeviceLimits::maxFramebufferLayers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-02516)"},
+    {"VUID-VkRenderPassCreateInfo-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkRenderPassFragmentDensityMapCreateInfoEXT, VkRenderPassInputAttachmentAspectCreateInfo, or VkRenderPassMultiviewCreateInfo (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pNext-pNext)"},
     {"VUID-VkRenderPassCreateInfo-pSubpasses-parameter", "pSubpasses must be a valid pointer to an array of subpassCount valid VkSubpassDescription structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pSubpasses-parameter)"},
     {"VUID-VkRenderPassCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-sType-sType)"},
     {"VUID-VkRenderPassCreateInfo-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-sType-unique)"},
+    {"VUID-VkRenderPassCreateInfo-srcSubpass-02517", "The srcSubpass member of each element of pDependencies must be less than subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-srcSubpass-02517)"},
     {"VUID-VkRenderPassCreateInfo-subpassCount-arraylength", "subpassCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-subpassCount-arraylength)"},
-    {"VUID-VkRenderPassCreateInfo2KHR-None-02348", "If any two subpasses activate transform feedback to the same bound transform feedback buffers a subpass dependency must be included (either directly or via some intermediate subpasses) between them (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-None-02348)"},
     {"VUID-VkRenderPassCreateInfo2KHR-None-03049", "If any two subpasses operate on attachments with overlapping ranges of the same VkDeviceMemory object, and at least one subpass writes to that area of VkDeviceMemory, a subpass dependency must be included (either directly or via some intermediate subpasses) between them (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-None-03049)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-attachment-02525", "If the attachment member of any element of the pInputAttachments member of any element of pSubpasses is not VK_ATTACHMENT_UNUSED, the aspectMask member of that element of pInputAttachments must only include aspects that are present in images of the format specified by the element of pAttachments specified by attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-attachment-02525)"},
     {"VUID-VkRenderPassCreateInfo2KHR-attachment-03050", "If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments or pDepthStencilAttachment, or the attachment indexed by any element of pPreserveAttachments in any given element of pSubpasses is bound to a range of a VkDeviceMemory object that overlaps with any other attachment in any subpass (including the same subpass), the VkAttachmentDescription2KHR structures describing them must include VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT in flags (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-attachment-03050)"},
     {"VUID-VkRenderPassCreateInfo2KHR-attachment-03051", "If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments or pDepthStencilAttachment, or any element of pPreserveAttachments in any given element of pSubpasses is not VK_ATTACHMENT_UNUSED, it must be less than attachmentCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-attachment-03051)"},
-    {"VUID-VkRenderPassCreateInfo2KHR-flags-parameter", "flags must be a valid combination of VkRenderPassCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-flags-parameter)"},
-    {"VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053", "For any member of pAttachments with a loadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-dstSubpass-02527", "The dstSubpass member of each element of pDependencies must be less than subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-dstSubpass-02527)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522", "For any member of pAttachments with a loadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-pAttachments-02523", "For any member of pAttachments with a stencilLoadOp equal to VK_ATTACHMENT_LOAD_OP_CLEAR, the first use of that attachment must not specify a layout equal to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pAttachments-02523)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pAttachments-parameter", "If attachmentCount is not 0, pAttachments must be a valid pointer to an array of attachmentCount valid VkAttachmentDescription2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pAttachments-parameter)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-03056", "The set of bits included in any element of pCorrelatedViewMasks must not overlap with the set of bits included in any other element of pCorrelatedViewMasks (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-03056)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-parameter", "If correlatedViewMaskCount is not 0, pCorrelatedViewMasks must be a valid pointer to an array of correlatedViewMaskCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-parameter)"},
@@ -1835,13 +1996,21 @@
     {"VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060", "For any element of pDependencies where its srcSubpass member equals its dstSubpass member, if the viewMask member of the corresponding element of pSubpasses includes more than one bit, its dependencyFlags member must include VK_DEPENDENCY_VIEW_LOCAL_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pDependencies-parameter", "If dependencyCount is not 0, pDependencies must be a valid pointer to an array of dependencyCount valid VkSubpassDependency2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pDependencies-parameter)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pNext-pNext)"},
-    {"VUID-VkRenderPassCreateInfo2KHR-pPreserveAttachments-03052", "The value of any element of the pPreserveAttachments member in any given element of pSubpasses must not be VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pPreserveAttachments-03052)"},
     {"VUID-VkRenderPassCreateInfo2KHR-pSubpasses-parameter", "pSubpasses must be a valid pointer to an array of subpassCount valid VkSubpassDescription2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-pSubpasses-parameter)"},
     {"VUID-VkRenderPassCreateInfo2KHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-sType-sType)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-srcSubpass-02526", "The srcSubpass member of each element of pDependencies must be less than subpassCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-srcSubpass-02526)"},
     {"VUID-VkRenderPassCreateInfo2KHR-subpassCount-arraylength", "subpassCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-subpassCount-arraylength)"},
+    {"VUID-VkRenderPassCreateInfo2KHR-viewMask-02524", "The viewMask member must not include a bit at a position greater than the value of VkPhysicalDeviceLimits::maxFramebufferLayers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-viewMask-02524)"},
     {"VUID-VkRenderPassCreateInfo2KHR-viewMask-03057", "If the VkSubpassDescription2KHR::viewMask member of all elements of pSubpasses is 0, correlatedViewMaskCount must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-viewMask-03057)"},
     {"VUID-VkRenderPassCreateInfo2KHR-viewMask-03058", "The VkSubpassDescription2KHR::viewMask member of all elements of pSubpasses must either all be 0, or all not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-viewMask-03058)"},
     {"VUID-VkRenderPassCreateInfo2KHR-viewMask-03059", "If the VkSubpassDescription2KHR::viewMask member of all elements of pSubpasses is 0, the dependencyFlags member of any element of pDependencies must not include VK_DEPENDENCY_VIEW_LOCAL_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo2KHR-viewMask-03059)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02547", "If fragmentDensityMapAttachment is not VK_ATTACHMENT_UNUSED, fragmentDensityMapAttachment must be less than VkRenderPassCreateInfo::attachmentCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02547)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02548", "If fragmentDensityMapAttachment is not VK_ATTACHMENT_UNUSED, fragmentDensityMapAttachment must not be an element of VkSubpassDescription::pInputAttachments, VkSubpassDescription::pColorAttachments, VkSubpassDescription::pResolveAttachments, VkSubpassDescription::pDepthStencilAttachment, or VkSubpassDescription::pPreserveAttachments for any subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02548)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02549", "If fragmentDensityMapAttachment is not VK_ATTACHMENT_UNUSED, layout must be equal to VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02549)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02550", "If fragmentDensityMapAttachment is not VK_ATTACHMENT_UNUSED, fragmentDensityMapAttachment must reference an attachment with a loadOp equal to VK_ATTACHMENT_LOAD_OP_LOAD or VK_ATTACHMENT_LOAD_OP_DONT_CARE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02550)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02551", "If fragmentDensityMapAttachment is not VK_ATTACHMENT_UNUSED, fragmentDensityMapAttachment must reference an attachment with a storeOp equal to VK_ATTACHMENT_STORE_OP_DONT_CARE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02551)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-parameter", "fragmentDensityMapAttachment must be a valid VkAttachmentReference structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-parameter)"},
+    {"VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-sType-sType)"},
     {"VUID-VkRenderPassInputAttachmentAspectCreateInfo-aspectReferenceCount-arraylength", "aspectReferenceCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassInputAttachmentAspectCreateInfo-aspectReferenceCount-arraylength)"},
     {"VUID-VkRenderPassInputAttachmentAspectCreateInfo-pAspectReferences-parameter", "pAspectReferences must be a valid pointer to an array of aspectReferenceCount valid VkInputAttachmentAspectReference structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassInputAttachmentAspectCreateInfo-pAspectReferences-parameter)"},
     {"VUID-VkRenderPassInputAttachmentAspectCreateInfo-sType-sType", "sType must be VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassInputAttachmentAspectCreateInfo-sType-sType)"},
@@ -1869,9 +2038,16 @@
     {"VUID-VkSamplerCreateInfo-anisotropyEnable-01071", "If anisotropyEnable is VK_TRUE, maxAnisotropy must be between 1.0 and VkPhysicalDeviceLimits::maxSamplerAnisotropy, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-anisotropyEnable-01071)"},
     {"VUID-VkSamplerCreateInfo-compareEnable-01080", "If compareEnable is VK_TRUE, compareOp must be a valid VkCompareOp value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-compareEnable-01080)"},
     {"VUID-VkSamplerCreateInfo-compareEnable-01423", "If compareEnable is VK_TRUE, the reductionMode member of VkSamplerReductionModeCreateInfoEXT must be VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-compareEnable-01423)"},
-    {"VUID-VkSamplerCreateInfo-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-zerobitmask)"},
-    {"VUID-VkSamplerCreateInfo-magFilter-01081", "If either magFilter or minFilter is VK_FILTER_CUBIC_IMG, anisotropyEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-magFilter-01081)"},
-    {"VUID-VkSamplerCreateInfo-magFilter-01422", "If either magFilter or minFilter is VK_FILTER_CUBIC_IMG, the reductionMode member of VkSamplerReductionModeCreateInfoEXT must be VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-magFilter-01422)"},
+    {"VUID-VkSamplerCreateInfo-flags-02574", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then minFilter and magFilter must be equal. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02574)"},
+    {"VUID-VkSamplerCreateInfo-flags-02575", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then mipmapMode must be VK_SAMPLER_MIPMAP_MODE_NEAREST. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02575)"},
+    {"VUID-VkSamplerCreateInfo-flags-02576", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then minLod and maxLod must be zero. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02576)"},
+    {"VUID-VkSamplerCreateInfo-flags-02577", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then addressModeU and addressModeV must each be either VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE or VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02577)"},
+    {"VUID-VkSamplerCreateInfo-flags-02578", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then anisotropyEnable must be VK_FALSE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02578)"},
+    {"VUID-VkSamplerCreateInfo-flags-02579", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then compareEnable must be VK_FALSE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02579)"},
+    {"VUID-VkSamplerCreateInfo-flags-02580", "If flags includes VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT, then unnormalizedCoordinates must be VK_FALSE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-02580)"},
+    {"VUID-VkSamplerCreateInfo-flags-parameter", "flags must be a valid combination of VkSamplerCreateFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-flags-parameter)"},
+    {"VUID-VkSamplerCreateInfo-magFilter-01081", "If either magFilter or minFilter is VK_FILTER_CUBIC_EXT, anisotropyEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-magFilter-01081)"},
+    {"VUID-VkSamplerCreateInfo-magFilter-01422", "If either magFilter or minFilter is VK_FILTER_CUBIC_EXT, the reductionMode member of VkSamplerReductionModeCreateInfoEXT must be VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-magFilter-01422)"},
     {"VUID-VkSamplerCreateInfo-magFilter-parameter", "magFilter must be a valid VkFilter value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-magFilter-parameter)"},
     {"VUID-VkSamplerCreateInfo-maxLod-01973", "maxLod must be greater than or equal to minLod (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-maxLod-01973)"},
     {"VUID-VkSamplerCreateInfo-minFilter-01645", "If sampler Y'CBCR conversion is enabled and VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT is not set for the format, minFilter and magFilter must be equal to the sampler Y'CBCR conversion's chromaFilter (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-minFilter-01645)"},
@@ -1889,9 +2065,13 @@
     {"VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01077", "If unnormalizedCoordinates is VK_TRUE, compareEnable must be VK_FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01077)"},
     {"VUID-VkSamplerReductionModeCreateInfoEXT-reductionMode-parameter", "reductionMode must be a valid VkSamplerReductionModeEXT value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerReductionModeCreateInfoEXT-reductionMode-parameter)"},
     {"VUID-VkSamplerReductionModeCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerReductionModeCreateInfoEXT-sType-sType)"},
-    {"VUID-VkSamplerYcbcrConversionCreateInfo-None-01654", "If the format has a _422 or _420 suffix: (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-None-01654)"},
     {"VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-01657", "If the format does not support VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, chromaFilter must be VK_FILTER_NEAREST (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-01657)"},
     {"VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-parameter", "chromaFilter must be a valid VkFilter value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-parameter)"},
+    {"VUID-VkSamplerYcbcrConversionCreateInfo-components-02581", "If the format has a _422 or _420 suffix, then components.g must be VK_COMPONENT_SWIZZLE_IDENTITY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-02581)"},
+    {"VUID-VkSamplerYcbcrConversionCreateInfo-components-02582", "If the format has a _422 or _420 suffix, then components.a must be VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE, or VK_COMPONENT_SWIZZLE_ZERO (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-02582)"},
+    {"VUID-VkSamplerYcbcrConversionCreateInfo-components-02583", "If the format has a _422 or _420 suffix, then components.r must be VK_COMPONENT_SWIZZLE_IDENTITY or VK_COMPONENT_SWIZZLE_B (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-02583)"},
+    {"VUID-VkSamplerYcbcrConversionCreateInfo-components-02584", "If the format has a _422 or _420 suffix, then components.b must be VK_COMPONENT_SWIZZLE_IDENTITY or VK_COMPONENT_SWIZZLE_R (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-02584)"},
+    {"VUID-VkSamplerYcbcrConversionCreateInfo-components-02585", "If the format has a _422 or _420 suffix, and if either components.r or components.b is VK_COMPONENT_SWIZZLE_IDENTITY, both values must be VK_COMPONENT_SWIZZLE_IDENTITY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-02585)"},
     {"VUID-VkSamplerYcbcrConversionCreateInfo-components-parameter", "components must be a valid VkComponentMapping structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-components-parameter)"},
     {"VUID-VkSamplerYcbcrConversionCreateInfo-forceExplicitReconstruction-01656", "If the format does not support VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, forceExplicitReconstruction must be FALSE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-forceExplicitReconstruction-01656)"},
     {"VUID-VkSamplerYcbcrConversionCreateInfo-format-01649", "format must not be VK_FORMAT_UNDEFINED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSamplerYcbcrConversionCreateInfo-format-01649)"},
@@ -2019,8 +2199,8 @@
     {"VUID-VkSubpassBeginInfoKHR-contents-parameter", "contents must be a valid VkSubpassContents value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassBeginInfoKHR-contents-parameter)"},
     {"VUID-VkSubpassBeginInfoKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassBeginInfoKHR-pNext-pNext)"},
     {"VUID-VkSubpassBeginInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassBeginInfoKHR-sType-sType)"},
-    {"VUID-VkSubpassDependency-dependencyFlags-00870", "If dependencyFlags includes VK_DEPENDENCY_VIEW_LOCAL_BIT, then both srcSubpass and dstSubpass must not equal VK_SUBPASS_EXTERNAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dependencyFlags-00870)"},
-    {"VUID-VkSubpassDependency-dependencyFlags-00871", "If dependencyFlags includes VK_DEPENDENCY_VIEW_LOCAL_BIT, then the render pass must have multiview enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dependencyFlags-00871)"},
+    {"VUID-VkSubpassDependency-dependencyFlags-02520", "If dependencyFlags includes VK_DEPENDENCY_VIEW_LOCAL_BIT, srcSubpass must not be equal to VK_SUBPASS_EXTERNAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dependencyFlags-02520)"},
+    {"VUID-VkSubpassDependency-dependencyFlags-02521", "If dependencyFlags includes VK_DEPENDENCY_VIEW_LOCAL_BIT, dstSubpass must not be equal to VK_SUBPASS_EXTERNAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dependencyFlags-02521)"},
     {"VUID-VkSubpassDependency-dependencyFlags-parameter", "dependencyFlags must be a valid combination of VkDependencyFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dependencyFlags-parameter)"},
     {"VUID-VkSubpassDependency-dstAccessMask-00869", "Any access flag included in dstAccessMask must be supported by one of the pipeline stages in dstStageMask, as specified in the table of supported access types (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dstAccessMask-00869)"},
     {"VUID-VkSubpassDependency-dstAccessMask-parameter", "dstAccessMask must be a valid combination of VkAccessFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency-dstAccessMask-parameter)"},
@@ -2074,54 +2254,73 @@
     {"VUID-VkSubpassDependency2KHR-srcSubpass-03084", "srcSubpass must be less than or equal to dstSubpass, unless one of them is VK_SUBPASS_EXTERNAL, to avoid cyclic dependencies and ensure a valid execution order (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency2KHR-srcSubpass-03084)"},
     {"VUID-VkSubpassDependency2KHR-srcSubpass-03085", "srcSubpass and dstSubpass must not both be equal to VK_SUBPASS_EXTERNAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency2KHR-srcSubpass-03085)"},
     {"VUID-VkSubpassDependency2KHR-srcSubpass-03087", "If srcSubpass is equal to dstSubpass and not all of the stages in srcStageMask and dstStageMask are framebuffer-space stages, the logically latest pipeline stage in srcStageMask must be logically earlier than or equal to the logically earliest pipeline stage in dstStageMask (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency2KHR-srcSubpass-03087)"},
+    {"VUID-VkSubpassDependency2KHR-viewOffset-02530", "If viewOffset is not equal to 0, srcSubpass must not be equal to dstSubpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency2KHR-viewOffset-02530)"},
     {"VUID-VkSubpassDependency2KHR-viewOffset-03093", "If viewOffset is not 0, srcSubpass must not be equal to dstSubpass. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDependency2KHR-viewOffset-03093)"},
-    {"VUID-VkSubpassDescription-None-00852", "If any input attachments are VK_ATTACHMENT_UNUSED, then any pipelines bound during the subpass must not access those input attachments from the fragment shader (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-None-00852)"},
     {"VUID-VkSubpassDescription-attachment-00853", "The attachment member of each element of pPreserveAttachments must not be VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-attachment-00853)"},
     {"VUID-VkSubpassDescription-colorAttachmentCount-00845", "colorAttachmentCount must be less than or equal to VkPhysicalDeviceLimits::maxColorAttachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-colorAttachmentCount-00845)"},
     {"VUID-VkSubpassDescription-flags-00856", "If flags includes VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX, it must also include VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-flags-00856)"},
     {"VUID-VkSubpassDescription-flags-parameter", "flags must be a valid combination of VkSubpassDescriptionFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-flags-parameter)"},
-    {"VUID-VkSubpassDescription-layout-00855", "If any attachment is used as both an input attachment and a color or depth/stencil attachment, then each use must use the same layout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-layout-00855)"},
+    {"VUID-VkSubpassDescription-layout-02519", "If any attachment is used by more than one VkAttachmentReference member, then each use must use the same layout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-layout-02519)"},
     {"VUID-VkSubpassDescription-loadOp-00846", "If the first use of an attachment in this render pass is as an input attachment, and the attachment is not also used as a color or depth/stencil attachment in the same subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-loadOp-00846)"},
     {"VUID-VkSubpassDescription-pColorAttachments-01417", "All attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pColorAttachments-01417)"},
-    {"VUID-VkSubpassDescription-pColorAttachments-01506", "All attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have a sample count that is smaller than or equal to the sample count of pDepthStencilAttachment if it is not VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pColorAttachments-01506)"},
+    {"VUID-VkSubpassDescription-pColorAttachments-01506", "If the VK_AMD_mixed_attachment_samples extension is enabled, and all attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have a sample count that is smaller than or equal to the sample count of pDepthStencilAttachment if it is not VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pColorAttachments-01506)"},
+    {"VUID-VkSubpassDescription-pColorAttachments-02648", "All attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have formats whose features contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pColorAttachments-02648)"},
     {"VUID-VkSubpassDescription-pColorAttachments-parameter", "If colorAttachmentCount is not 0, pColorAttachments must be a valid pointer to an array of colorAttachmentCount valid VkAttachmentReference structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pColorAttachments-parameter)"},
-    {"VUID-VkSubpassDescription-pDepthStencilAttachment-01418", "If pDepthStencilAttachment is not VK_ATTACHMENT_UNUSED and any attachments in pColorAttachments are not VK_ATTACHMENT_UNUSED, they must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pDepthStencilAttachment-01418)"},
+    {"VUID-VkSubpassDescription-pDepthStencilAttachment-01418", "If neither the VK_AMD_mixed_attachment_samples nor the VK_NV_framebuffer_mixed_samples extensions are enabled, and if pDepthStencilAttachment is not VK_ATTACHMENT_UNUSED and any attachments in pColorAttachments are not VK_ATTACHMENT_UNUSED, they must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pDepthStencilAttachment-01418)"},
+    {"VUID-VkSubpassDescription-pDepthStencilAttachment-02650", "If pDepthStencilAttachment is not NULL and the attachment is not VK_ATTACHMENT_UNUSED then it must have a format whose features contain VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pDepthStencilAttachment-02650)"},
     {"VUID-VkSubpassDescription-pDepthStencilAttachment-parameter", "If pDepthStencilAttachment is not NULL, pDepthStencilAttachment must be a valid pointer to a valid VkAttachmentReference structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pDepthStencilAttachment-parameter)"},
+    {"VUID-VkSubpassDescription-pInputAttachments-02647", "All attachments in pInputAttachments that are not VK_ATTACHMENT_UNUSED must have formats whose features contain at least one of VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT or VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pInputAttachments-02647)"},
     {"VUID-VkSubpassDescription-pInputAttachments-parameter", "If inputAttachmentCount is not 0, pInputAttachments must be a valid pointer to an array of inputAttachmentCount valid VkAttachmentReference structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pInputAttachments-parameter)"},
     {"VUID-VkSubpassDescription-pPreserveAttachments-00854", "Each element of pPreserveAttachments must not also be an element of any other member of the subpass description (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pPreserveAttachments-00854)"},
     {"VUID-VkSubpassDescription-pPreserveAttachments-parameter", "If preserveAttachmentCount is not 0, pPreserveAttachments must be a valid pointer to an array of preserveAttachmentCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pPreserveAttachments-parameter)"},
-    {"VUID-VkSubpassDescription-pResolveAttachments-00847", "If pResolveAttachments is not NULL, for each resolve attachment that does not have the value VK_ATTACHMENT_UNUSED, the corresponding color attachment must not have the value VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00847)"},
-    {"VUID-VkSubpassDescription-pResolveAttachments-00848", "If pResolveAttachments is not NULL, the sample count of each element of pColorAttachments must be anything other than VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00848)"},
-    {"VUID-VkSubpassDescription-pResolveAttachments-00849", "Each element of pResolveAttachments must have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00849)"},
-    {"VUID-VkSubpassDescription-pResolveAttachments-00850", "Each element of pResolveAttachments must have the same VkFormat as its corresponding color attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00850)"},
+    {"VUID-VkSubpassDescription-pResolveAttachments-00847", "If pResolveAttachments is not NULL, for each resolve attachment that is not VK_ATTACHMENT_UNUSED, the corresponding color attachment must not be VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00847)"},
+    {"VUID-VkSubpassDescription-pResolveAttachments-00848", "If pResolveAttachments is not NULL, for each resolve attachment that is not VK_ATTACHMENT_UNUSED, the corresponding color attachment must not have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00848)"},
+    {"VUID-VkSubpassDescription-pResolveAttachments-00849", "If pResolveAttachments is not NULL, each resolve attachment that is not VK_ATTACHMENT_UNUSED must have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00849)"},
+    {"VUID-VkSubpassDescription-pResolveAttachments-00850", "If pResolveAttachments is not NULL, each resolve attachment that is not VK_ATTACHMENT_UNUSED must have the same VkFormat as its corresponding color attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00850)"},
+    {"VUID-VkSubpassDescription-pResolveAttachments-02649", "All attachments in pResolveAttachments that are not VK_ATTACHMENT_UNUSED must have formats whose features contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-02649)"},
     {"VUID-VkSubpassDescription-pResolveAttachments-parameter", "If colorAttachmentCount is not 0, and pResolveAttachments is not NULL, pResolveAttachments must be a valid pointer to an array of colorAttachmentCount valid VkAttachmentReference structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-parameter)"},
     {"VUID-VkSubpassDescription-pipelineBindPoint-00844", "pipelineBindPoint must be VK_PIPELINE_BIND_POINT_GRAPHICS (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pipelineBindPoint-00844)"},
     {"VUID-VkSubpassDescription-pipelineBindPoint-parameter", "pipelineBindPoint must be a valid VkPipelineBindPoint value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pipelineBindPoint-parameter)"},
-    {"VUID-VkSubpassDescription2KHR-None-03072", "If any input attachments are VK_ATTACHMENT_UNUSED, then any pipelines bound during the subpass must not access those input attachments from the fragment shader (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-None-03072)"},
+    {"VUID-VkSubpassDescription2KHR-aspectMask-02529", "The aspectMask member of each element of pInputAttachments must not include VK_IMAGE_ASPECT_METADATA_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-aspectMask-02529)"},
     {"VUID-VkSubpassDescription2KHR-aspectMask-03175", "The aspectMask member of any element of pInputAttachments must be a valid combination of VkImageAspectFlagBits (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-aspectMask-03175)"},
     {"VUID-VkSubpassDescription2KHR-aspectMask-03176", "The aspectMask member of any element of pInputAttachments must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-aspectMask-03176)"},
     {"VUID-VkSubpassDescription2KHR-attachment-03073", "The attachment member of any element of pPreserveAttachments must not be VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-attachment-03073)"},
     {"VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063", "colorAttachmentCount must be less than or equal to VkPhysicalDeviceLimits::maxColorAttachments (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063)"},
     {"VUID-VkSubpassDescription2KHR-flags-03076", "If flags includes VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX, it must also include VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-flags-03076)"},
     {"VUID-VkSubpassDescription2KHR-flags-parameter", "flags must be a valid combination of VkSubpassDescriptionFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-flags-parameter)"},
-    {"VUID-VkSubpassDescription2KHR-layout-03075", "If any attachment is used as both an input attachment and a color or depth/stencil attachment, then each use must use the same layout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-layout-03075)"},
+    {"VUID-VkSubpassDescription2KHR-layout-02528", "If any attachment is used by more than one VkAttachmentReference member, then each use must use the same layout (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-layout-02528)"},
     {"VUID-VkSubpassDescription2KHR-loadOp-03064", "If the first use of an attachment in this render pass is as an input attachment, and the attachment is not also used as a color or depth/stencil attachment in the same subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-loadOp-03064)"},
     {"VUID-VkSubpassDescription2KHR-pColorAttachments-03069", "All attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pColorAttachments-03069)"},
-    {"VUID-VkSubpassDescription2KHR-pColorAttachments-03070", "All attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have a sample count that is smaller than or equal to the sample count of pDepthStencilAttachment if it is not VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pColorAttachments-03070)"},
+    {"VUID-VkSubpassDescription2KHR-pColorAttachments-03070", "If the VK_AMD_mixed_attachment_samples extension is enabled, all attachments in pColorAttachments that are not VK_ATTACHMENT_UNUSED must have a sample count that is smaller than or equal to the sample count of pDepthStencilAttachment if it is not VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pColorAttachments-03070)"},
     {"VUID-VkSubpassDescription2KHR-pColorAttachments-parameter", "If colorAttachmentCount is not 0, pColorAttachments must be a valid pointer to an array of colorAttachmentCount valid VkAttachmentReference2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pColorAttachments-parameter)"},
-    {"VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071", "If pDepthStencilAttachment is not VK_ATTACHMENT_UNUSED and any attachments in pColorAttachments are not VK_ATTACHMENT_UNUSED, they must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071)"},
+    {"VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071", "If neither the VK_AMD_mixed_attachment_samples nor the VK_NV_framebuffer_mixed_samples extensions are enabled, and if pDepthStencilAttachment is not VK_ATTACHMENT_UNUSED and any attachments in pColorAttachments are not VK_ATTACHMENT_UNUSED, they must have the same sample count (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071)"},
     {"VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-parameter", "If pDepthStencilAttachment is not NULL, pDepthStencilAttachment must be a valid pointer to a valid VkAttachmentReference2KHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-parameter)"},
     {"VUID-VkSubpassDescription2KHR-pInputAttachments-parameter", "If inputAttachmentCount is not 0, pInputAttachments must be a valid pointer to an array of inputAttachmentCount valid VkAttachmentReference2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pInputAttachments-parameter)"},
     {"VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074", "Any given element of pPreserveAttachments must not also be an element of any other member of the subpass description (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074)"},
     {"VUID-VkSubpassDescription2KHR-pPreserveAttachments-parameter", "If preserveAttachmentCount is not 0, pPreserveAttachments must be a valid pointer to an array of preserveAttachmentCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pPreserveAttachments-parameter)"},
     {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03065", "If pResolveAttachments is not NULL, for each resolve attachment that does not have the value VK_ATTACHMENT_UNUSED, the corresponding color attachment must not have the value VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03065)"},
-    {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03066", "If pResolveAttachments is not NULL, the sample count of each element of pColorAttachments must be anything other than VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03066)"},
-    {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03067", "Any given element of pResolveAttachments must have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03067)"},
+    {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03066", "If pResolveAttachments is not NULL, for each resolve attachment that is not VK_ATTACHMENT_UNUSED, the corresponding color attachment must not have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03066)"},
+    {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03067", "If pResolveAttachments is not NULL, each resolve attachment that is not VK_ATTACHMENT_UNUSED must have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03067)"},
     {"VUID-VkSubpassDescription2KHR-pResolveAttachments-03068", "Any given element of pResolveAttachments must have the same VkFormat as its corresponding color attachment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-03068)"},
     {"VUID-VkSubpassDescription2KHR-pResolveAttachments-parameter", "If colorAttachmentCount is not 0, and pResolveAttachments is not NULL, pResolveAttachments must be a valid pointer to an array of colorAttachmentCount valid VkAttachmentReference2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pResolveAttachments-parameter)"},
     {"VUID-VkSubpassDescription2KHR-pipelineBindPoint-03062", "pipelineBindPoint must be VK_PIPELINE_BIND_POINT_GRAPHICS (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pipelineBindPoint-03062)"},
     {"VUID-VkSubpassDescription2KHR-pipelineBindPoint-parameter", "pipelineBindPoint must be a valid VkPipelineBindPoint value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-pipelineBindPoint-parameter)"},
     {"VUID-VkSubpassDescription2KHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription2KHR-sType-sType)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-depthResolveMode-03183", "The value of depthResolveMode must be one of the bits set in VkPhysicalDeviceDepthStencilResolvePropertiesKHR::supportedDepthResolveModes or VK_RESOLVE_MODE_NONE_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-depthResolveMode-03183)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-depthResolveMode-parameter", "depthResolveMode must be a valid VkResolveModeFlagBitsKHR value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-depthResolveMode-parameter)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-02651", "If pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED then it must have a format whose features contain VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-02651)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03177", "If pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED, pDepthStencilAttachment must not have the value VK_ATTACHMENT_UNUSED (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03177)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03178", "If pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED, depthResolveMode and stencilResolveMode must not both be VK_RESOLVE_MODE_NONE_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03178)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03179", "If pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED, pDepthStencilAttachment must not have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03179)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03180", "If pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED, pDepthStencilResolveAttachment must have a sample count of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03180)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03181", "If the VkFormat of pDepthStencilResolveAttachment has a depth component, then the VkFormat of pDepthStencilAttachment must have a depth component with the same number of bits and numerical type (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03181)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03182", "If the VkFormat of pDepthStencilResolveAttachment has a stencil component, then the VkFormat of pDepthStencilAttachment must have a stencil component with the same number of bits and numerical type (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03182)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03185", "If the VkFormat of pDepthStencilResolveAttachment has both depth and stencil components, VkPhysicalDeviceDepthStencilResolvePropertiesKHR::independentResolve is VK_FALSE, and VkPhysicalDeviceDepthStencilResolvePropertiesKHR::independentResolveNone is VK_FALSE, then the values of depthResolveMode and stencilResolveMode must be identical (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03185)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03186", "If the VkFormat of pDepthStencilResolveAttachment has both depth and stencil components, VkPhysicalDeviceDepthStencilResolvePropertiesKHR::independentResolve is VK_FALSE and VkPhysicalDeviceDepthStencilResolvePropertiesKHR::independentResolveNone is VK_TRUE, then the values of depthResolveMode and stencilResolveMode must be identical or one of them must be VK_RESOLVE_MODE_NONE_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-03186)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-parameter", "If pDepthStencilResolveAttachment is not NULL, pDepthStencilResolveAttachment must be a valid pointer to a valid VkAttachmentReference2KHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-pDepthStencilResolveAttachment-parameter)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-sType-sType)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-stencilResolveMode-03184", "The value of stencilResolveMode must be one of the bits set in VkPhysicalDeviceDepthStencilResolvePropertiesKHR::supportedStencilResolveModes or VK_RESOLVE_MODE_NONE_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-stencilResolveMode-03184)"},
+    {"VUID-VkSubpassDescriptionDepthStencilResolveKHR-stencilResolveMode-parameter", "stencilResolveMode must be a valid VkResolveModeFlagBitsKHR value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescriptionDepthStencilResolveKHR-stencilResolveMode-parameter)"},
     {"VUID-VkSubpassEndInfoKHR-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassEndInfoKHR-pNext-pNext)"},
     {"VUID-VkSubpassEndInfoKHR-sType-sType", "sType must be VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassEndInfoKHR-sType-sType)"},
     {"VUID-VkSubpassSampleLocationsEXT-sampleLocationsInfo-parameter", "sampleLocationsInfo must be a valid VkSampleLocationsInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassSampleLocationsEXT-sampleLocationsInfo-parameter)"},
@@ -2139,13 +2338,14 @@
     {"VUID-VkSwapchainCreateInfoKHR-commonparent", "Both of oldSwapchain, and surface that are valid handles must have been created, allocated, or retrieved from the same VkInstance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-commonparent)"},
     {"VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280", "compositeAlpha must be one of the bits present in the supportedCompositeAlpha member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280)"},
     {"VUID-VkSwapchainCreateInfoKHR-compositeAlpha-parameter", "compositeAlpha must be a valid VkCompositeAlphaFlagBitsKHR value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-compositeAlpha-parameter)"},
+    {"VUID-VkSwapchainCreateInfoKHR-flags-03168", "If flags contains VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR then the pNext chain must contain an instance of VkImageFormatListCreateInfoKHR with a viewFormatCount greater than zero and pViewFormats must have an element equal to imageFormat (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-flags-03168)"},
     {"VUID-VkSwapchainCreateInfoKHR-flags-parameter", "flags must be a valid combination of VkSwapchainCreateFlagBitsKHR values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-flags-parameter)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275", "imageArrayLayers must be greater than 0 and less than or equal to the maxImageArrayLayers member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageColorSpace-parameter", "imageColorSpace must be a valid VkColorSpaceKHR value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageColorSpace-parameter)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageExtent-01274", "imageExtent must be between minImageExtent and maxImageExtent, inclusive, where minImageExtent and maxImageExtent are members of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01274)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageExtent-01689", "imageExtent members width and height must both be non-zero (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01689)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageFormat-01273", "imageFormat and imageColorSpace must match the format and colorSpace members, respectively, of one of the VkSurfaceFormatKHR structures returned by vkGetPhysicalDeviceSurfaceFormatsKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-01273)"},
-    {"VUID-VkSwapchainCreateInfoKHR-imageFormat-01778", "imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-01778)"},
+    {"VUID-VkSwapchainCreateInfoKHR-imageFormat-01778", "The implied image creation parameters of the swapchain must be supported as reported by vkGetPhysicalDeviceImageFormatProperties (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-01778)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageFormat-parameter", "imageFormat must be a valid VkFormat value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-parameter)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01277", "If imageSharingMode is VK_SHARING_MODE_CONCURRENT, pQueueFamilyIndices must be a valid pointer to an array of queueFamilyIndexCount uint32_t values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01277)"},
     {"VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01278", "If imageSharingMode is VK_SHARING_MODE_CONCURRENT, queueFamilyIndexCount must be greater than 1 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01278)"},
@@ -2162,7 +2362,7 @@
     {"VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933", "If oldSwapchain is not VK_NULL_HANDLE, oldSwapchain must be a non-retired swapchain associated with native window referred to by surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933)"},
     {"VUID-VkSwapchainCreateInfoKHR-oldSwapchain-parameter", "If oldSwapchain is not VK_NULL_HANDLE, oldSwapchain must be a valid VkSwapchainKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-oldSwapchain-parameter)"},
     {"VUID-VkSwapchainCreateInfoKHR-oldSwapchain-parent", "If oldSwapchain is a valid handle, it must have been created, allocated, or retrieved from surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-oldSwapchain-parent)"},
-    {"VUID-VkSwapchainCreateInfoKHR-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDeviceGroupSwapchainCreateInfoKHR or VkSwapchainCounterCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-pNext-pNext)"},
+    {"VUID-VkSwapchainCreateInfoKHR-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDeviceGroupSwapchainCreateInfoKHR, VkImageFormatListCreateInfoKHR, or VkSwapchainCounterCreateInfoEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-pNext-pNext)"},
     {"VUID-VkSwapchainCreateInfoKHR-physicalDeviceCount-01429", "If the logical device was created with VkDeviceGroupDeviceCreateInfo::physicalDeviceCount equal to 1, flags must not contain VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-physicalDeviceCount-01429)"},
     {"VUID-VkSwapchainCreateInfoKHR-preTransform-01279", "preTransform must be one of the bits present in the supportedTransforms member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-preTransform-01279)"},
     {"VUID-VkSwapchainCreateInfoKHR-preTransform-parameter", "preTransform must be a valid VkSurfaceTransformFlagBitsKHR value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-preTransform-parameter)"},
@@ -2173,12 +2373,16 @@
     {"VUID-VkSwapchainCreateInfoKHR-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-sType-unique)"},
     {"VUID-VkSwapchainCreateInfoKHR-surface-01270", "surface must be a surface that is supported by the device as determined using vkGetPhysicalDeviceSurfaceSupportKHR (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-surface-01270)"},
     {"VUID-VkSwapchainCreateInfoKHR-surface-parameter", "surface must be a valid VkSurfaceKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-surface-parameter)"},
+    {"VUID-VkTextureLODGatherFormatPropertiesAMD-sType-sType", "sType must be VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkTextureLODGatherFormatPropertiesAMD-sType-sType)"},
     {"VUID-VkValidationCacheCreateInfoEXT-flags-zerobitmask", "flags must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-flags-zerobitmask)"},
     {"VUID-VkValidationCacheCreateInfoEXT-initialDataSize-01534", "If initialDataSize is not 0, it must be equal to the size of pInitialData, as returned by vkGetValidationCacheDataEXT when pInitialData was originally retrieved (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-initialDataSize-01534)"},
     {"VUID-VkValidationCacheCreateInfoEXT-initialDataSize-01535", "If initialDataSize is not 0, pInitialData must have been retrieved from a previous call to vkGetValidationCacheDataEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-initialDataSize-01535)"},
     {"VUID-VkValidationCacheCreateInfoEXT-pInitialData-parameter", "If initialDataSize is not 0, pInitialData must be a valid pointer to an array of initialDataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-pInitialData-parameter)"},
     {"VUID-VkValidationCacheCreateInfoEXT-pNext-pNext", "pNext must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-pNext-pNext)"},
     {"VUID-VkValidationCacheCreateInfoEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationCacheCreateInfoEXT-sType-sType)"},
+    {"VUID-VkValidationFeaturesEXT-pDisabledValidationFeatures-parameter", "If disabledValidationFeatureCount is not 0, pDisabledValidationFeatures must be a valid pointer to an array of disabledValidationFeatureCount valid VkValidationFeatureDisableEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFeaturesEXT-pDisabledValidationFeatures-parameter)"},
+    {"VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-parameter", "If enabledValidationFeatureCount is not 0, pEnabledValidationFeatures must be a valid pointer to an array of enabledValidationFeatureCount valid VkValidationFeatureEnableEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-parameter)"},
+    {"VUID-VkValidationFeaturesEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFeaturesEXT-sType-sType)"},
     {"VUID-VkValidationFlagsEXT-disabledValidationCheckCount-arraylength", "disabledValidationCheckCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFlagsEXT-disabledValidationCheckCount-arraylength)"},
     {"VUID-VkValidationFlagsEXT-pDisabledValidationChecks-parameter", "pDisabledValidationChecks must be a valid pointer to an array of disabledValidationCheckCount valid VkValidationCheckEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFlagsEXT-pDisabledValidationChecks-parameter)"},
     {"VUID-VkValidationFlagsEXT-sType-sType", "sType must be VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkValidationFlagsEXT-sType-sType)"},
@@ -2202,11 +2406,9 @@
     {"VUID-VkViewport-height-01772", "height must be greater than 0.0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-height-01772)"},
     {"VUID-VkViewport-height-01773", "The absolute value of height must be less than or equal to VkPhysicalDeviceLimits::maxViewportDimensions[1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-height-01773)"},
     {"VUID-VkViewport-maxDepth-01235", "Unless VK_EXT_depth_range_unrestricted extension is enabled maxDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-maxDepth-01235)"},
-    {"VUID-VkViewport-maxDepth-01235[(VK_EXT_depth_range_unrestricted)]", "Unless VK_EXT_depth_range_unrestricted extension is enabled maxDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-maxDepth-01235)"},
-    {"VUID-VkViewport-maxDepth-01235[!(VK_EXT_depth_range_unrestricted)]", "maxDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-maxDepth-01235)"},
+    {"VUID-VkViewport-maxDepth-02541", "maxDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-maxDepth-02541)"},
     {"VUID-VkViewport-minDepth-01234", "Unless VK_EXT_depth_range_unrestricted extension is enabled minDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-minDepth-01234)"},
-    {"VUID-VkViewport-minDepth-01234[(VK_EXT_depth_range_unrestricted)]", "Unless VK_EXT_depth_range_unrestricted extension is enabled minDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-minDepth-01234)"},
-    {"VUID-VkViewport-minDepth-01234[!(VK_EXT_depth_range_unrestricted)]", "minDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-minDepth-01234)"},
+    {"VUID-VkViewport-minDepth-02540", "minDepth must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-minDepth-02540)"},
     {"VUID-VkViewport-width-01770", "width must be greater than 0.0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-width-01770)"},
     {"VUID-VkViewport-width-01771", "width must be less than or equal to VkPhysicalDeviceLimits::maxViewportDimensions[0] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-width-01771)"},
     {"VUID-VkViewport-x-01232", "(x + width) must be less than or equal to viewportBoundsRange[1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkViewport-x-01232)"},
@@ -2269,21 +2471,26 @@
     {"VUID-VkWriteDescriptorSet-descriptorType-00338", "If descriptorType is VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView member of each element of pImageInfo must have been created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-00338)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-00339", "If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, the imageView member of each element of pImageInfo must have been created with VK_IMAGE_USAGE_STORAGE_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-00339)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-01402", "If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, for each descriptor that will be accessed via load or store operations the imageLayout member for corresponding elements of pImageInfo must be VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01402)"},
-    {"VUID-VkWriteDescriptorSet-descriptorType-01403", "If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, the imageLayout member of each element of pImageInfo must be VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01403)"},
+    {"VUID-VkWriteDescriptorSet-descriptorType-01403", "If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, the imageLayout member of each element of pImageInfo must be a member of the list given in Sampled Image or Combined Image Sampler, corresponding to its type (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01403)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-01946", "If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, then the imageView member of each pImageInfo element must have been created without a VkSamplerYcbcrConversionInfo structure in its pNext chain (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01946)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-01947", "If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and if any element of pImageInfo has a imageView member that was created with a VkSamplerYcbcrConversionInfo structure in its pNext chain, then dstSet must have been allocated with a layout that included immutable samplers for dstBinding (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01947)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-01948", "If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and dstSet was allocated with a layout that included immutable samplers for dstBinding, then the imageView member of each element of pImageInfo which corresponds to an immutable sampler that enables sampler Y'CBCR conversion must have been created with a VkSamplerYcbcrConversionInfo structure in its pNext chain with an identically defined VkSamplerYcbcrConversionInfo to the corresponding immutable sampler (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-01948)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-02219", "If descriptorType is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, dstArrayElement must be an integer multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-02219)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-02220", "If descriptorType is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, descriptorCount must be an integer multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-02220)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-02221", "If descriptorType is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, the pNext chain must include a VkWriteDescriptorSetInlineUniformBlockEXT structure whose dataSize member equals descriptorCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-02221)"},
+    {"VUID-VkWriteDescriptorSet-descriptorType-02382", "If descriptorType is VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, the pNext chain must include a VkWriteDescriptorSetAccelerationStructureNV structure whose accelerationStructureCount member equals descriptorCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-02382)"},
     {"VUID-VkWriteDescriptorSet-descriptorType-parameter", "descriptorType must be a valid VkDescriptorType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-parameter)"},
     {"VUID-VkWriteDescriptorSet-dstArrayElement-00321", "The sum of dstArrayElement and descriptorCount must be less than or equal to the number of array elements in the descriptor set binding specified by dstBinding, and all applicable consecutive bindings, as described by consecutive binding updates (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-dstArrayElement-00321)"},
     {"VUID-VkWriteDescriptorSet-dstBinding-00315", "dstBinding must be less than or equal to the maximum value of binding of all VkDescriptorSetLayoutBinding structures specified when dstSet's descriptor set layout was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-dstBinding-00315)"},
     {"VUID-VkWriteDescriptorSet-dstBinding-00316", "dstBinding must be a binding with a non-zero descriptorCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-dstBinding-00316)"},
     {"VUID-VkWriteDescriptorSet-dstSet-00320", "dstSet must be a valid VkDescriptorSet handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-dstSet-00320)"},
-    {"VUID-VkWriteDescriptorSet-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDescriptorAccelerationStructureInfoNVX or VkWriteDescriptorSetInlineUniformBlockEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-pNext-pNext)"},
+    {"VUID-VkWriteDescriptorSet-pNext-pNext", "Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkWriteDescriptorSetAccelerationStructureNV or VkWriteDescriptorSetInlineUniformBlockEXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-pNext-pNext)"},
     {"VUID-VkWriteDescriptorSet-sType-sType", "sType must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-sType-sType)"},
     {"VUID-VkWriteDescriptorSet-sType-unique", "Each sType member in the pNext chain must be unique (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-sType-unique)"},
+    {"VUID-VkWriteDescriptorSetAccelerationStructureNV-accelerationStructureCount-02236", "accelerationStructureCount must be equal to descriptorCount in the extended structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetAccelerationStructureNV-accelerationStructureCount-02236)"},
+    {"VUID-VkWriteDescriptorSetAccelerationStructureNV-accelerationStructureCount-arraylength", "accelerationStructureCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetAccelerationStructureNV-accelerationStructureCount-arraylength)"},
+    {"VUID-VkWriteDescriptorSetAccelerationStructureNV-pAccelerationStructures-parameter", "pAccelerationStructures must be a valid pointer to an array of accelerationStructureCount valid VkAccelerationStructureNV handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetAccelerationStructureNV-pAccelerationStructures-parameter)"},
+    {"VUID-VkWriteDescriptorSetAccelerationStructureNV-sType-sType", "sType must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetAccelerationStructureNV-sType-sType)"},
     {"VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-02222", "dataSize must be an integer multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-02222)"},
     {"VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-arraylength", "dataSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-arraylength)"},
     {"VUID-VkWriteDescriptorSetInlineUniformBlockEXT-pData-parameter", "pData must be a valid pointer to an array of dataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSetInlineUniformBlockEXT-pData-parameter)"},
@@ -2337,9 +2544,9 @@
     {"VUID-vkBeginCommandBuffer-commandBuffer-00052", "If commandBuffer is a secondary command buffer and either the occlusionQueryEnable member of the pInheritanceInfo member of pBeginInfo is VK_FALSE, or the precise occlusion queries feature is not enabled, the queryFlags member of the pInheritanceInfo member pBeginInfo must not contain VK_QUERY_CONTROL_PRECISE_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-00052)"},
     {"VUID-vkBeginCommandBuffer-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-commandBuffer-parameter)"},
     {"VUID-vkBeginCommandBuffer-pBeginInfo-parameter", "pBeginInfo must be a valid pointer to a valid VkCommandBufferBeginInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBeginCommandBuffer-pBeginInfo-parameter)"},
-    {"VUID-vkBindAccelerationStructureMemoryNVX-bindInfoCount-arraylength", "bindInfoCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNVX-bindInfoCount-arraylength)"},
-    {"VUID-vkBindAccelerationStructureMemoryNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNVX-device-parameter)"},
-    {"VUID-vkBindAccelerationStructureMemoryNVX-pBindInfos-parameter", "pBindInfos must be a valid pointer to an array of bindInfoCount valid VkBindAccelerationStructureMemoryInfoNVX structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNVX-pBindInfos-parameter)"},
+    {"VUID-vkBindAccelerationStructureMemoryNV-bindInfoCount-arraylength", "bindInfoCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNV-bindInfoCount-arraylength)"},
+    {"VUID-vkBindAccelerationStructureMemoryNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNV-device-parameter)"},
+    {"VUID-vkBindAccelerationStructureMemoryNV-pBindInfos-parameter", "pBindInfos must be a valid pointer to an array of bindInfoCount valid VkBindAccelerationStructureMemoryInfoNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindAccelerationStructureMemoryNV-pBindInfos-parameter)"},
     {"VUID-vkBindBufferMemory-None-01898", "If buffer was created with the VK_BUFFER_CREATE_PROTECTED_BIT bit set, the buffer must be bound to a memory object allocated with a memory type that reports VK_MEMORY_PROPERTY_PROTECTED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindBufferMemory-None-01898)"},
     {"VUID-vkBindBufferMemory-None-01899", "If buffer was created with the VK_BUFFER_CREATE_PROTECTED_BIT bit not set, the buffer must not be bound to a memory object created with a memory type that reports VK_MEMORY_PROPERTY_PROTECTED_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindBufferMemory-None-01899)"},
     {"VUID-vkBindBufferMemory-buffer-01029", "buffer must not already be backed by a memory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindBufferMemory-buffer-01029)"},
@@ -2373,6 +2580,8 @@
     {"VUID-vkBindImageMemory-image-parent", "image must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-image-parent)"},
     {"VUID-vkBindImageMemory-memory-01047", "memory must have been allocated using one of the memory types allowed in the memoryTypeBits member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-01047)"},
     {"VUID-vkBindImageMemory-memory-01509", "If the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then image must equal VkMemoryDedicatedAllocateInfo::image and memoryOffset must be zero. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-01509)"},
+    {"VUID-vkBindImageMemory-memory-02628", "If the dedicated allocation image aliasing feature is not enabled, and the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then image must equal VkMemoryDedicatedAllocateInfo::image and memoryOffset must be zero. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-02628)"},
+    {"VUID-vkBindImageMemory-memory-02629", "If the dedicated allocation image aliasing feature is enabled, and the VkMemoryAllocateInfo provided when memory was allocated included an instance of VkMemoryDedicatedAllocateInfo in its pNext chain, and VkMemoryDedicatedAllocateInfo::image was not VK_NULL_HANDLE, then memoryOffset must be zero, and image must be either equal to VkMemoryDedicatedAllocateInfo::image or an image that was created using the same parameters in VkImageCreateInfo, with the exception that extent and arrayLayers may differ subject to the following restrictions: every dimension in the extent parameter of the image being bound must be equal to or smaller than the original image for which the allocation was created; and the arrayLayers parameter of the image being bound must be equal to or smaller than the original image for which the allocation was created. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-02629)"},
     {"VUID-vkBindImageMemory-memory-parameter", "memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-parameter)"},
     {"VUID-vkBindImageMemory-memory-parent", "memory must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memory-parent)"},
     {"VUID-vkBindImageMemory-memoryOffset-01046", "memoryOffset must be less than the size of memory (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memoryOffset-01046)"},
@@ -2431,44 +2640,45 @@
     {"VUID-vkCmdBeginRenderPass-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-commandBuffer-parameter)"},
     {"VUID-vkCmdBeginRenderPass-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-commandBuffer-recording)"},
     {"VUID-vkCmdBeginRenderPass-contents-parameter", "contents must be a valid VkSubpassContents value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-contents-parameter)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-00895", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00895)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-00896", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00896)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-00897", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00897)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-00898", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00898)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-00899", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_TRANSFER_DST_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00899)"},
+    {"VUID-vkCmdBeginRenderPass-framebuffer-02532", "For any attachment in framebuffer that is used by renderPass and is bound to memory locations that are also bound to another attachment used by renderPass, and if at least one of those uses causes either attachment to be written to, both attachments must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-framebuffer-02532)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-00895", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00895)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-00896", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00896)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-00897", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00897)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-00898", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_TRANSFER_SRC_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00898)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-00899", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_TRANSFER_DST_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00899)"},
     {"VUID-vkCmdBeginRenderPass-initialLayout-00900", "If any of the initialLayout members of the VkAttachmentDescription structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is not VK_IMAGE_LAYOUT_UNDEFINED, then each such initialLayout must be equal to the current layout of the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00900)"},
-    {"VUID-vkCmdBeginRenderPass-initialLayout-01758", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-01758)"},
+    {"VUID-vkCmdBeginRenderPass-initialLayout-01758", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-01758)"},
     {"VUID-vkCmdBeginRenderPass-pRenderPassBegin-parameter", "pRenderPassBegin must be a valid pointer to a valid VkRenderPassBeginInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-pRenderPassBegin-parameter)"},
     {"VUID-vkCmdBeginRenderPass-renderpass", "This command must only be called outside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-renderpass)"},
-    {"VUID-vkCmdBeginRenderPass-srcStageMask-00901", "The srcStageMask and dstStageMask members of any element of the pDependencies member of VkRenderPassCreateInfo used to create renderPass must be supported by the capabilities of the queue family identified by the queueFamilyIndex member of the VkCommandPoolCreateInfo used to create the command pool which commandBuffer was allocated from. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-srcStageMask-00901)"},
+    {"VUID-vkCmdBeginRenderPass-srcStageMask-00901", "The srcStageMask and dstStageMask members of any element of the pDependencies member of VkRenderPassCreateInfo used to create renderPass must be supported by the capabilities of the queue family identified by the queueFamilyIndex member of the VkCommandPoolCreateInfo used to create the command pool which commandBuffer was allocated from (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass-srcStageMask-00901)"},
     {"VUID-vkCmdBeginRenderPass2KHR-bufferlevel", "commandBuffer must be a primary VkCommandBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-bufferlevel)"},
     {"VUID-vkCmdBeginRenderPass2KHR-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-commandBuffer-cmdpool)"},
     {"VUID-vkCmdBeginRenderPass2KHR-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-commandBuffer-parameter)"},
     {"VUID-vkCmdBeginRenderPass2KHR-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-commandBuffer-recording)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03095", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03095)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with VK_IMAGE_USAGE_TRANSFER_DST_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-framebuffer-02533", "For any attachment in framebuffer that is used by renderPass and is bound to memory locations that are also bound to another attachment used by renderPass, and if at least one of those uses causes either attachment to be written to, both attachments must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-framebuffer-02533)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_SAMPLED_BIT or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_TRANSFER_SRC_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099", "If any of the initialLayout or finalLayout member of the VkAttachmentDescription structures or the layout member of the VkAttachmentReference structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL then the corresponding attachment image view of the framebuffer specified in the framebuffer member of pRenderPassBegin must have been created with a usage value including VK_IMAGE_USAGE_TRANSFER_DST_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099)"},
     {"VUID-vkCmdBeginRenderPass2KHR-initialLayout-03100", "If any of the initialLayout members of the VkAttachmentDescription structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is not VK_IMAGE_LAYOUT_UNDEFINED, then each such initialLayout must be equal to the current layout of the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-initialLayout-03100)"},
     {"VUID-vkCmdBeginRenderPass2KHR-pRenderPassBegin-parameter", "pRenderPassBegin must be a valid pointer to a valid VkRenderPassBeginInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-pRenderPassBegin-parameter)"},
     {"VUID-vkCmdBeginRenderPass2KHR-pSubpassBeginInfo-parameter", "pSubpassBeginInfo must be a valid pointer to a valid VkSubpassBeginInfoKHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-pSubpassBeginInfo-parameter)"},
     {"VUID-vkCmdBeginRenderPass2KHR-renderpass", "This command must only be called outside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-renderpass)"},
-    {"VUID-vkCmdBeginRenderPass2KHR-srcStageMask-03101", "The srcStageMask and dstStageMask members of any element of the pDependencies member of VkRenderPassCreateInfo used to create renderPass must be supported by the capabilities of the queue family identified by the queueFamilyIndex member of the VkCommandPoolCreateInfo used to create the command pool which commandBuffer was allocated from. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-srcStageMask-03101)"},
+    {"VUID-vkCmdBeginRenderPass2KHR-srcStageMask-03101", "The srcStageMask and dstStageMask members of any element of the pDependencies member of VkRenderPassCreateInfo used to create renderPass must be supported by the capabilities of the queue family identified by the queueFamilyIndex member of the VkCommandPoolCreateInfo used to create the command pool which commandBuffer was allocated from (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginRenderPass2KHR-srcStageMask-03101)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-None-02367", "Transform feedback must not be active (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-None-02367)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-None-02373", "Transform feedback must not be made active in a render pass instance with multiview enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-None-02373)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-cmdpool)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-parameter)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-commandBuffer-recording)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-commonparent", "Both of commandBuffer, and the elements of pCounterBuffers that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-commonparent)"},
+    {"VUID-vkCmdBeginTransformFeedbackEXT-counterBufferCount-02607", "If counterBufferCount is not 0, and pCounterBuffers is not NULL, pCounterBuffers must be a valid pointer to an array of counterBufferCount VkBuffer handles that are either valid or VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-counterBufferCount-02607)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-firstCounterBuffer-02368", "firstCounterBuffer must be less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-firstCounterBuffer-02368)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-firstCounterBuffer-02369", "The sum of firstCounterBuffer and counterBufferCount must be less than or equal to VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-firstCounterBuffer-02369)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffer-02371", "If pCounterBuffer is NULL, then pCounterBufferOffsets must also be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffer-02371)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-pCounterBufferOffsets-02370", "For each buffer handle in the array, if it is not VK_NULL_HANDLE it must reference a buffer large enough to hold 4 bytes at the corresponding offset from the pCounterBufferOffsets array (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-pCounterBufferOffsets-02370)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-pCounterBufferOffsets-parameter", "If counterBufferCount is not 0, and pCounterBufferOffsets is not NULL, pCounterBufferOffsets must be a valid pointer to an array of counterBufferCount VkDeviceSize values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-pCounterBufferOffsets-parameter)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffers-02372", "For each buffer handle in the pCounterBuffers array that is not VK_NULL_HANDLE it must have been created with a usage value containing VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffers-02372)"},
-    {"VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffers-parameter", "If counterBufferCount is not 0, and pCounterBuffers is not NULL, pCounterBuffers must be a valid pointer to an array of counterBufferCount valid VkBuffer handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffers-parameter)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-renderpass", "This command must only be called inside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-renderpass)"},
     {"VUID-vkCmdBeginTransformFeedbackEXT-transformFeedback-02366", "VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBeginTransformFeedbackEXT-transformFeedback-02366)"},
     {"VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool)"},
@@ -2494,6 +2704,7 @@
     {"VUID-vkCmdBindIndexBuffer-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-commandBuffer-parameter)"},
     {"VUID-vkCmdBindIndexBuffer-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-commandBuffer-recording)"},
     {"VUID-vkCmdBindIndexBuffer-commonparent", "Both of buffer, and commandBuffer must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-commonparent)"},
+    {"VUID-vkCmdBindIndexBuffer-indexType-02507", "indexType must not be VK_INDEX_TYPE_NONE_NV. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-indexType-02507)"},
     {"VUID-vkCmdBindIndexBuffer-indexType-parameter", "indexType must be a valid VkIndexType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-indexType-parameter)"},
     {"VUID-vkCmdBindIndexBuffer-offset-00431", "offset must be less than the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-offset-00431)"},
     {"VUID-vkCmdBindIndexBuffer-offset-00432", "The sum of offset and the address of the range of VkDeviceMemory object that is backing buffer, must be a multiple of the type indicated by indexType (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindIndexBuffer-offset-00432)"},
@@ -2508,6 +2719,8 @@
     {"VUID-vkCmdBindPipeline-pipelineBindPoint-00778", "If pipelineBindPoint is VK_PIPELINE_BIND_POINT_GRAPHICS, the VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-00778)"},
     {"VUID-vkCmdBindPipeline-pipelineBindPoint-00779", "If pipelineBindPoint is VK_PIPELINE_BIND_POINT_COMPUTE, pipeline must be a compute pipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-00779)"},
     {"VUID-vkCmdBindPipeline-pipelineBindPoint-00780", "If pipelineBindPoint is VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline must be a graphics pipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-00780)"},
+    {"VUID-vkCmdBindPipeline-pipelineBindPoint-02391", "If pipelineBindPoint is VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, the VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-02391)"},
+    {"VUID-vkCmdBindPipeline-pipelineBindPoint-02392", "If pipelineBindPoint is VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, the pipeline must be a ray tracing pipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-02392)"},
     {"VUID-vkCmdBindPipeline-pipelineBindPoint-parameter", "pipelineBindPoint must be a valid VkPipelineBindPoint value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-pipelineBindPoint-parameter)"},
     {"VUID-vkCmdBindPipeline-variableSampleLocations-01525", "If VkPhysicalDeviceSampleLocationsPropertiesEXT::variableSampleLocations is VK_FALSE, and pipeline is a graphics pipeline created with a VkPipelineSampleLocationsStateCreateInfoEXT structure having its sampleLocationsEnable member set to VK_TRUE but without VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT enabled then the current render pass instance must have been begun by specifying a VkRenderPassSampleLocationsBeginInfoEXT structure whose pPostSubpassSampleLocations member contains an element with a subpassIndex matching the current subpass index and the sampleLocationsInfo member of that element must match the sampleLocationsInfo specified in VkPipelineSampleLocationsStateCreateInfoEXT when the pipeline was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindPipeline-variableSampleLocations-01525)"},
     {"VUID-vkCmdBindShadingRateImageNV-None-02058", "The shading rate image feature must be enabled. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-None-02058)"},
@@ -2519,7 +2732,7 @@
     {"VUID-vkCmdBindShadingRateImageNV-imageLayout-parameter", "imageLayout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageLayout-parameter)"},
     {"VUID-vkCmdBindShadingRateImageNV-imageView-02059", "If imageView is not VK_NULL_HANDLE, it must be a valid VkImageView handle of type VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-02059)"},
     {"VUID-vkCmdBindShadingRateImageNV-imageView-02060", "If imageView is not VK_NULL_HANDLE, it must have a format of VK_FORMAT_R8_UINT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-02060)"},
-    {"VUID-vkCmdBindShadingRateImageNV-imageView-02061", "If imageView is not VK_NULL_HANDLE, the image must have been created with VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-02061)"},
+    {"VUID-vkCmdBindShadingRateImageNV-imageView-02061", "If imageView is not VK_NULL_HANDLE, it must have been created with a usage value including VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-02061)"},
     {"VUID-vkCmdBindShadingRateImageNV-imageView-02062", "If imageView is not VK_NULL_HANDLE, imageLayout must match the actual VkImageLayout of each subresource accessible from imageView at the time the subresource is accessed. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-02062)"},
     {"VUID-vkCmdBindShadingRateImageNV-imageView-parameter", "imageView must be a valid VkImageView handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindShadingRateImageNV-imageView-parameter)"},
     {"VUID-vkCmdBindTransformFeedbackBuffersEXT-None-02365", "Transform feedback must not be active when the vkCmdBindTransformFeedbackBuffersEXT command is recorded (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBindTransformFeedbackBuffersEXT-None-02365)"},
@@ -2565,6 +2778,7 @@
     {"VUID-vkCmdBlitImage-dstImage-00234", "dstImage must have been created with a samples value of VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImage-00234)"},
     {"VUID-vkCmdBlitImage-dstImage-01562", "dstImage must not use a format listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImage-01562)"},
     {"VUID-vkCmdBlitImage-dstImage-02000", "The format features of dstImage must contain VK_FORMAT_FEATURE_BLIT_DST_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImage-02000)"},
+    {"VUID-vkCmdBlitImage-dstImage-02545", "dstImage and srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImage-02545)"},
     {"VUID-vkCmdBlitImage-dstImage-parameter", "dstImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImage-parameter)"},
     {"VUID-vkCmdBlitImage-dstImageLayout-00226", "dstImageLayout must specify the layout of the image subresources of dstImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImageLayout-00226)"},
     {"VUID-vkCmdBlitImage-dstImageLayout-00227", "dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImageLayout-00227)"},
@@ -2572,9 +2786,9 @@
     {"VUID-vkCmdBlitImage-dstImageLayout-parameter", "dstImageLayout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstImageLayout-parameter)"},
     {"VUID-vkCmdBlitImage-dstSubresource-01706", "The dstSubresource.mipLevel member of each element of pRegions must be less than the mipLevels specified in VkImageCreateInfo when dstImage was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstSubresource-01706)"},
     {"VUID-vkCmdBlitImage-dstSubresource-01708", "The dstSubresource.baseArrayLayer + dstSubresource.layerCount of each element of pRegions must be less than or equal to the arrayLayers specified in VkImageCreateInfo when dstImage was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-dstSubresource-01708)"},
-    {"VUID-vkCmdBlitImage-filter-00237", "If filter is VK_FILTER_CUBIC_IMG, srcImage must have a VkImageType of VK_IMAGE_TYPE_2D (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-00237)"},
+    {"VUID-vkCmdBlitImage-filter-00237", "If filter is VK_FILTER_CUBIC_EXT, srcImage must have a VkImageType of VK_IMAGE_TYPE_2D (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-00237)"},
     {"VUID-vkCmdBlitImage-filter-02001", "If filter is VK_FILTER_LINEAR, then the format features of srcImage must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-02001)"},
-    {"VUID-vkCmdBlitImage-filter-02002", "If filter is VK_FILTER_CUBIC_IMG, then the format features of srcImage must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-02002)"},
+    {"VUID-vkCmdBlitImage-filter-02002", "If filter is VK_FILTER_CUBIC_EXT, then the format features of srcImage must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-02002)"},
     {"VUID-vkCmdBlitImage-filter-parameter", "filter must be a valid VkFilter value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-filter-parameter)"},
     {"VUID-vkCmdBlitImage-pRegions-00215", "The source region specified by each element of pRegions must be a region that is contained within srcImage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-pRegions-00215)"},
     {"VUID-vkCmdBlitImage-pRegions-00216", "The destination region specified by each element of pRegions must be a region that is contained within dstImage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-pRegions-00216)"},
@@ -2599,21 +2813,28 @@
     {"VUID-vkCmdBlitImage-srcImageLayout-parameter", "srcImageLayout must be a valid VkImageLayout value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-srcImageLayout-parameter)"},
     {"VUID-vkCmdBlitImage-srcSubresource-01705", "The srcSubresource.mipLevel member of each element of pRegions must be less than the mipLevels specified in VkImageCreateInfo when srcImage was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-srcSubresource-01705)"},
     {"VUID-vkCmdBlitImage-srcSubresource-01707", "The srcSubresource.baseArrayLayer + srcSubresource.layerCount of each element of pRegions must be less than or equal to the arrayLayers specified in VkImageCreateInfo when srcImage was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBlitImage-srcSubresource-01707)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-cmdpool)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-commandBuffer-recording)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-commonparent", "Each of commandBuffer, dst, instanceData, scratch, and src that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-commonparent)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-dst-parameter", "dst must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-dst-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-flags-parameter", "flags must be a valid combination of VkBuildAccelerationStructureFlagBitsNVX values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-flags-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-geometryCount-02241", "geometryCount must be less than or equal to VkPhysicalDeviceRaytracingPropertiesNVX::maxGeometryCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-geometryCount-02241)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-instanceData-parameter", "If instanceData is not VK_NULL_HANDLE, instanceData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-instanceData-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-pGeometries-parameter", "If geometryCount is not 0, pGeometries must be a valid pointer to an array of geometryCount valid VkGeometryNVX structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-pGeometries-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-scratch-parameter", "scratch must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-scratch-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-src-parameter", "If src is not VK_NULL_HANDLE, src must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-src-parameter)"},
-    {"VUID-vkCmdBuildAccelerationStructureNVX-type-parameter", "type must be a valid VkAccelerationStructureTypeNVX value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNVX-type-parameter)"},
-    {"VUID-vkCmdClearAttachments-aspectMask-00015", "If the aspectMask member of any element of pAttachments contains VK_IMAGE_ASPECT_COLOR_BIT, the colorAttachment member of that element must refer to a valid color attachment in the current subpass (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-aspectMask-00015)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-cmdpool)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-commandBuffer-recording)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-commonparent", "Each of commandBuffer, dst, instanceData, scratch, and src that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-commonparent)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-dst-02488", "dst must have been created with compatible VkAccelerationStructureInfoNV where VkAccelerationStructureInfoNV:::type and VkAccelerationStructureInfoNV::flags are identical, VkAccelerationStructureInfoNV::instanceCount and VkAccelerationStructureInfoNV::geometryCount for dst are greater than or equal to the build size and each geometry in VkAccelerationStructureInfoNV::pGeometries for dst has greater than or equal to the number of vertices, indices, and AABBs. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-dst-02488)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-dst-parameter", "dst must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-dst-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-geometryCount-02241", "geometryCount must be less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-geometryCount-02241)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-instanceData-parameter", "If instanceData is not VK_NULL_HANDLE, instanceData must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-instanceData-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-pInfo-parameter", "pInfo must be a valid pointer to a valid VkAccelerationStructureInfoNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-pInfo-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-scratch-parameter", "scratch must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-scratch-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-src-parameter", "If src is not VK_NULL_HANDLE, src must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-src-parameter)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-update-02489", "If update is VK_TRUE, src must not be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-update-02489)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-update-02490", "If update is VK_TRUE, src must have been built before with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV set in VkAccelerationStructureInfoNV::flags (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-update-02490)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-update-02491", "If update is VK_FALSE, The size member of the VkMemoryRequirements structure returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and VkAccelerationStructureMemoryRequirementsInfoNV::type set to VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV must be less than or equal to the size of scratch minus scratchOffset (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-update-02491)"},
+    {"VUID-vkCmdBuildAccelerationStructureNV-update-02492", "If update is VK_TRUE, The size member of the VkMemoryRequirements structure returned from a call to vkGetAccelerationStructureMemoryRequirementsNV with VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and VkAccelerationStructureMemoryRequirementsInfoNV::type set to VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV must be less than or equal to the size of scratch minus scratchOffset (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdBuildAccelerationStructureNV-update-02492)"},
+    {"VUID-vkCmdClearAttachments-aspectMask-02501", "If the aspectMask member of any element of pAttachments contains VK_IMAGE_ASPECT_COLOR_BIT, then the colorAttachment member of that element must either refer to a color attachment which is VK_ATTACHMENT_UNUSED, or must be a valid color attachment. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-aspectMask-02501)"},
+    {"VUID-vkCmdClearAttachments-aspectMask-02502", "If the aspectMask member of any element of pAttachments contains VK_IMAGE_ASPECT_DEPTH_BIT, then the current subpass' depth/stencil attachment must either be VK_ATTACHMENT_UNUSED, or must have a depth component (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-aspectMask-02502)"},
+    {"VUID-vkCmdClearAttachments-aspectMask-02503", "If the aspectMask member of any element of pAttachments contains VK_IMAGE_ASPECT_STENCIL_BIT, then the current subpass' depth/stencil attachment must either be VK_ATTACHMENT_UNUSED, or must have a stencil component (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-aspectMask-02503)"},
     {"VUID-vkCmdClearAttachments-attachmentCount-arraylength", "attachmentCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-attachmentCount-arraylength)"},
     {"VUID-vkCmdClearAttachments-baseArrayLayer-00018", "If the render pass instance this is recorded in uses multiview, then baseArrayLayer must be zero and layerCount must be one. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-baseArrayLayer-00018)"},
+    {"VUID-vkCmdClearAttachments-commandBuffer-02504", "If commandBuffer is an unprotected command buffer, then each attachment to be cleared must not be a protected image. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-commandBuffer-02504)"},
+    {"VUID-vkCmdClearAttachments-commandBuffer-02505", "If commandBuffer is a protected command buffer, then each attachment to be cleared must not be an unprotected image. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-commandBuffer-02505)"},
     {"VUID-vkCmdClearAttachments-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-commandBuffer-cmdpool)"},
     {"VUID-vkCmdClearAttachments-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-commandBuffer-parameter)"},
     {"VUID-vkCmdClearAttachments-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-commandBuffer-recording)"},
@@ -2624,6 +2845,7 @@
     {"VUID-vkCmdClearAttachments-pRects-parameter", "pRects must be a valid pointer to an array of rectCount VkClearRect structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-pRects-parameter)"},
     {"VUID-vkCmdClearAttachments-rectCount-arraylength", "rectCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-rectCount-arraylength)"},
     {"VUID-vkCmdClearAttachments-renderpass", "This command must only be called inside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearAttachments-renderpass)"},
+    {"VUID-vkCmdClearColorImage-aspectMask-02498", "The VkImageSubresourceRange::aspectMask members of the elements of the pRanges array must each only include VK_IMAGE_ASPECT_COLOR_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-aspectMask-02498)"},
     {"VUID-vkCmdClearColorImage-baseArrayLayer-01472", "The VkImageSubresourceRange::baseArrayLayer members of the elements of the pRanges array must each be less than the arrayLayers specified in VkImageCreateInfo when image was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-baseArrayLayer-01472)"},
     {"VUID-vkCmdClearColorImage-baseMipLevel-01470", "The VkImageSubresourceRange::baseMipLevel members of the elements of the pRanges array must each be less than the mipLevels specified in VkImageCreateInfo when image was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-baseMipLevel-01470)"},
     {"VUID-vkCmdClearColorImage-commandBuffer-01805", "If commandBuffer is an unprotected command buffer, then image must not be a protected image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-commandBuffer-01805)"},
@@ -2648,6 +2870,8 @@
     {"VUID-vkCmdClearColorImage-pRanges-parameter", "pRanges must be a valid pointer to an array of rangeCount valid VkImageSubresourceRange structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-pRanges-parameter)"},
     {"VUID-vkCmdClearColorImage-rangeCount-arraylength", "rangeCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-rangeCount-arraylength)"},
     {"VUID-vkCmdClearColorImage-renderpass", "This command must only be called outside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearColorImage-renderpass)"},
+    {"VUID-vkCmdClearDepthStencilImage-aspectMask-02499", "The VkImageSubresourceRange::aspectMask members of the elements of the pRanges array must each only include VK_IMAGE_ASPECT_DEPTH_BIT if the image format has a depth component (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-aspectMask-02499)"},
+    {"VUID-vkCmdClearDepthStencilImage-aspectMask-02500", "The VkImageSubresourceRange::aspectMask members of the elements of the pRanges array must each only include VK_IMAGE_ASPECT_STENCIL_BIT if the image format has a stencil component (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-aspectMask-02500)"},
     {"VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476", "The VkImageSubresourceRange::baseArrayLayer members of the elements of the pRanges array must each be less than the arrayLayers specified in VkImageCreateInfo when image was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476)"},
     {"VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474", "The VkImageSubresourceRange::baseMipLevel members of the elements of the pRanges array must each be less than the mipLevels specified in VkImageCreateInfo when image was created (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474)"},
     {"VUID-vkCmdClearDepthStencilImage-commandBuffer-01807", "If commandBuffer is an unprotected command buffer, then image must not be a protected image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-commandBuffer-01807)"},
@@ -2670,13 +2894,15 @@
     {"VUID-vkCmdClearDepthStencilImage-pRanges-parameter", "pRanges must be a valid pointer to an array of rangeCount valid VkImageSubresourceRange structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-pRanges-parameter)"},
     {"VUID-vkCmdClearDepthStencilImage-rangeCount-arraylength", "rangeCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-rangeCount-arraylength)"},
     {"VUID-vkCmdClearDepthStencilImage-renderpass", "This command must only be called outside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdClearDepthStencilImage-renderpass)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-cmdpool)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-parameter)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-commandBuffer-recording)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-commonparent", "Each of commandBuffer, dst, and src must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-commonparent)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-dst-parameter", "dst must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-dst-parameter)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-mode-parameter", "mode must be a valid VkCopyAccelerationStructureModeNVX value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-mode-parameter)"},
-    {"VUID-vkCmdCopyAccelerationStructureNVX-src-parameter", "src must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNVX-src-parameter)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-cmdpool)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-parameter)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-commandBuffer-recording)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-commonparent", "Each of commandBuffer, dst, and src must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-commonparent)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-dst-parameter", "dst must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-dst-parameter)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-mode-02496", "mode must be VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV or VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-mode-02496)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-mode-parameter", "mode must be a valid VkCopyAccelerationStructureModeNV value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-mode-parameter)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-src-02497", "src must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV if mode is VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-src-02497)"},
+    {"VUID-vkCmdCopyAccelerationStructureNV-src-parameter", "src must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyAccelerationStructureNV-src-parameter)"},
     {"VUID-vkCmdCopyBuffer-commandBuffer-01822", "If commandBuffer is an unprotected command buffer, then srcBuffer must not be a protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBuffer-commandBuffer-01822)"},
     {"VUID-vkCmdCopyBuffer-commandBuffer-01823", "If commandBuffer is an unprotected command buffer, then dstBuffer must not be a protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBuffer-commandBuffer-01823)"},
     {"VUID-vkCmdCopyBuffer-commandBuffer-01824", "If commandBuffer is a protected command buffer, then dstBuffer must not be an unprotected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBuffer-commandBuffer-01824)"},
@@ -2709,6 +2935,7 @@
     {"VUID-vkCmdCopyBufferToImage-dstImage-00178", "If dstImage is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImage-00178)"},
     {"VUID-vkCmdCopyBufferToImage-dstImage-00179", "dstImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImage-00179)"},
     {"VUID-vkCmdCopyBufferToImage-dstImage-01997", "The format features of dstImage must contain VK_FORMAT_FEATURE_TRANSFER_DST_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImage-01997)"},
+    {"VUID-vkCmdCopyBufferToImage-dstImage-02543", "dstImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImage-02543)"},
     {"VUID-vkCmdCopyBufferToImage-dstImage-parameter", "dstImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImage-parameter)"},
     {"VUID-vkCmdCopyBufferToImage-dstImageLayout-00180", "dstImageLayout must specify the layout of the image subresources of dstImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImageLayout-00180)"},
     {"VUID-vkCmdCopyBufferToImage-dstImageLayout-00181", "dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImageLayout-00181)"},
@@ -2739,6 +2966,7 @@
     {"VUID-vkCmdCopyImage-dstImage-00132", "If dstImage is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImage-00132)"},
     {"VUID-vkCmdCopyImage-dstImage-01547", "If dstImage is non-sparse then the image or disjoint plane that is the destination of the copy must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImage-01547)"},
     {"VUID-vkCmdCopyImage-dstImage-01996", "The format features of dstImage must contain VK_FORMAT_FEATURE_TRANSFER_DST_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImage-01996)"},
+    {"VUID-vkCmdCopyImage-dstImage-02542", "dstImage and srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImage-02542)"},
     {"VUID-vkCmdCopyImage-dstImage-parameter", "dstImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImage-parameter)"},
     {"VUID-vkCmdCopyImage-dstImageLayout-00133", "dstImageLayout must specify the layout of the image subresources of dstImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImageLayout-00133)"},
     {"VUID-vkCmdCopyImage-dstImageLayout-00134", "dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-dstImageLayout-00134)"},
@@ -2755,10 +2983,10 @@
     {"VUID-vkCmdCopyImage-renderpass", "This command must only be called outside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-renderpass)"},
     {"VUID-vkCmdCopyImage-srcImage-00126", "srcImage must have been created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-00126)"},
     {"VUID-vkCmdCopyImage-srcImage-00127", "If srcImage is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-00127)"},
-    {"VUID-vkCmdCopyImage-srcImage-00135", "The VkFormat of each of srcImage and dstImage must be compatible, as defined below (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-00135)"},
+    {"VUID-vkCmdCopyImage-srcImage-00135", "The VkFormat of each of srcImage and dstImage must be compatible, as defined above (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-00135)"},
     {"VUID-vkCmdCopyImage-srcImage-00136", "The sample count of srcImage and dstImage must match (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-00136)"},
     {"VUID-vkCmdCopyImage-srcImage-01546", "If srcImage is non-sparse then the image or disjoint plane to be copied must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-01546)"},
-    {"VUID-vkCmdCopyImage-srcImage-01548", "If the VkFormat of each of srcImage and dstImage is not a multi-planar format, the VkFormat of each of srcImage and dstImage must be compatible, as defined below (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-01548)"},
+    {"VUID-vkCmdCopyImage-srcImage-01548", "If the VkFormat of each of srcImage and dstImage is not a multi-planar format, the VkFormat of each of srcImage and dstImage must be compatible, as defined above (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-01548)"},
     {"VUID-vkCmdCopyImage-srcImage-01995", "The format features of srcImage must contain VK_FORMAT_FEATURE_TRANSFER_SRC_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-01995)"},
     {"VUID-vkCmdCopyImage-srcImage-parameter", "srcImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImage-parameter)"},
     {"VUID-vkCmdCopyImage-srcImageLayout-00128", "srcImageLayout must specify the layout of the image subresources of srcImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImage-srcImageLayout-00128)"},
@@ -2791,6 +3019,7 @@
     {"VUID-vkCmdCopyImageToBuffer-srcImage-00187", "If srcImage is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImage-00187)"},
     {"VUID-vkCmdCopyImageToBuffer-srcImage-00188", "srcImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImage-00188)"},
     {"VUID-vkCmdCopyImageToBuffer-srcImage-01998", "The format features of srcImage must contain VK_FORMAT_FEATURE_TRANSFER_SRC_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImage-01998)"},
+    {"VUID-vkCmdCopyImageToBuffer-srcImage-02544", "srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImage-02544)"},
     {"VUID-vkCmdCopyImageToBuffer-srcImage-parameter", "srcImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImage-parameter)"},
     {"VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189", "srcImageLayout must specify the layout of the image subresources of srcImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189)"},
     {"VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190", "srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190)"},
@@ -2835,15 +3064,17 @@
     {"VUID-vkCmdDispatch-None-00395", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_COMPUTE uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-00395)"},
     {"VUID-vkCmdDispatch-None-00396", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-00396)"},
     {"VUID-vkCmdDispatch-None-00397", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-00397)"},
-    {"VUID-vkCmdDispatch-None-00400", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-00400)"},
-    {"VUID-vkCmdDispatch-None-02005", "If a VkImageView is sampled with with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02005)"},
-    {"VUID-vkCmdDispatch-None-02006", "If a VkImageView is sampled with with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02006)"},
+    {"VUID-vkCmdDispatch-None-00400", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-00400)"},
+    {"VUID-vkCmdDispatch-None-02005", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02005)"},
+    {"VUID-vkCmdDispatch-None-02006", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02006)"},
     {"VUID-vkCmdDispatch-commandBuffer-01844", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-01844)"},
-    {"VUID-vkCmdDispatch-commandBuffer-01845", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_POINT_COMPUTE writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-01845)"},
-    {"VUID-vkCmdDispatch-commandBuffer-01846", "If commandBuffer is a protected command buffer, and any pipeline stage other than the compute pipeline stage in the VkPipeline object bound to VK_PIPELINE_POINT_COMPUTE reads from any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-01846)"},
+    {"VUID-vkCmdDispatch-commandBuffer-01845", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-01845)"},
+    {"VUID-vkCmdDispatch-commandBuffer-01846", "If commandBuffer is a protected command buffer, and any pipeline stage other than the compute pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE reads from any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-01846)"},
     {"VUID-vkCmdDispatch-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDispatch-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-parameter)"},
     {"VUID-vkCmdDispatch-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-commandBuffer-recording)"},
+    {"VUID-vkCmdDispatch-filterCubic-02609", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubic-02609)"},
+    {"VUID-vkCmdDispatch-filterCubicMinmax-02610", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubicMinmax-02610)"},
     {"VUID-vkCmdDispatch-flags-02040", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-flags-02040)"},
     {"VUID-vkCmdDispatch-groupCountX-00386", "groupCountX must be less than or equal to VkPhysicalDeviceLimits::maxComputeWorkGroupCount[0] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-groupCountX-00386)"},
     {"VUID-vkCmdDispatch-groupCountY-00387", "groupCountY must be less than or equal to VkPhysicalDeviceLimits::maxComputeWorkGroupCount[1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatch-groupCountY-00387)"},
@@ -2870,19 +3101,20 @@
     {"VUID-vkCmdDispatchIndirect-None-00411", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_COMPUTE uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-00411)"},
     {"VUID-vkCmdDispatchIndirect-None-00412", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-00412)"},
     {"VUID-vkCmdDispatchIndirect-None-00413", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-00413)"},
-    {"VUID-vkCmdDispatchIndirect-None-00416", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-00416)"},
-    {"VUID-vkCmdDispatchIndirect-None-02007", "If a VkImageView is sampled with with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-02007)"},
-    {"VUID-vkCmdDispatchIndirect-None-02008", "If a VkImageView is sampled with with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-02008)"},
+    {"VUID-vkCmdDispatchIndirect-None-00416", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-00416)"},
+    {"VUID-vkCmdDispatchIndirect-None-02007", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-02007)"},
+    {"VUID-vkCmdDispatchIndirect-None-02008", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-None-02008)"},
     {"VUID-vkCmdDispatchIndirect-buffer-00401", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-buffer-00401)"},
     {"VUID-vkCmdDispatchIndirect-buffer-00405", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-buffer-00405)"},
     {"VUID-vkCmdDispatchIndirect-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-buffer-parameter)"},
     {"VUID-vkCmdDispatchIndirect-commandBuffer-01847", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_COMPUTE reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-01847)"},
-    {"VUID-vkCmdDispatchIndirect-commandBuffer-01848", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_POINT_COMPUTE writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-01848)"},
-    {"VUID-vkCmdDispatchIndirect-commandBuffer-01849", "If commandBuffer is a protected command buffer, and any pipeline stage other than the compute pipeline stage in the VkPipeline object bound to VK_PIPELINE_POINT_COMPUTE reads from any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-01849)"},
+    {"VUID-vkCmdDispatchIndirect-commandBuffer-02639", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-02639)"},
     {"VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDispatchIndirect-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-parameter)"},
     {"VUID-vkCmdDispatchIndirect-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commandBuffer-recording)"},
     {"VUID-vkCmdDispatchIndirect-commonparent", "Both of buffer, and commandBuffer must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-commonparent)"},
+    {"VUID-vkCmdDispatchIndirect-filterCubic-02611", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-filterCubic-02611)"},
+    {"VUID-vkCmdDispatchIndirect-filterCubicMinmax-02612", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-filterCubicMinmax-02612)"},
     {"VUID-vkCmdDispatchIndirect-flags-02041", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-flags-02041)"},
     {"VUID-vkCmdDispatchIndirect-offset-00406", "offset must be a multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-offset-00406)"},
     {"VUID-vkCmdDispatchIndirect-offset-00407", "The sum of offset and the size of VkDispatchIndirectCommand must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDispatchIndirect-offset-00407)"},
@@ -2900,16 +3132,18 @@
     {"VUID-vkCmdDraw-None-00447", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-00447)"},
     {"VUID-vkCmdDraw-None-00448", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-00448)"},
     {"VUID-vkCmdDraw-None-00449", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-00449)"},
-    {"VUID-vkCmdDraw-None-00452", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-00452)"},
+    {"VUID-vkCmdDraw-None-00452", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-00452)"},
     {"VUID-vkCmdDraw-None-01499", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-01499)"},
     {"VUID-vkCmdDraw-None-02009", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-02009)"},
-    {"VUID-vkCmdDraw-None-02010", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-02010)"},
+    {"VUID-vkCmdDraw-None-02010", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-None-02010)"},
     {"VUID-vkCmdDraw-commandBuffer-01850", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-01850)"},
     {"VUID-vkCmdDraw-commandBuffer-01851", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-01851)"},
     {"VUID-vkCmdDraw-commandBuffer-01852", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-01852)"},
     {"VUID-vkCmdDraw-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDraw-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-parameter)"},
     {"VUID-vkCmdDraw-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-commandBuffer-recording)"},
+    {"VUID-vkCmdDraw-filterCubic-02613", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-filterCubic-02613)"},
+    {"VUID-vkCmdDraw-filterCubicMinmax-02614", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-filterCubicMinmax-02614)"},
     {"VUID-vkCmdDraw-flags-02042", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-flags-02042)"},
     {"VUID-vkCmdDraw-maxMultiviewInstanceIndex-00453", "If the draw is recorded in a render pass instance with multiview enabled, the maximum instance index must be less than or equal to VkPhysicalDeviceMultiviewProperties::maxMultiviewInstanceIndex. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-maxMultiviewInstanceIndex-00453)"},
     {"VUID-vkCmdDraw-renderPass-00435", "The current render pass must be compatible with the renderPass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDraw-renderPass-00435)"},
@@ -2929,16 +3163,18 @@
     {"VUID-vkCmdDrawIndexed-None-00467", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-00467)"},
     {"VUID-vkCmdDrawIndexed-None-00468", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-00468)"},
     {"VUID-vkCmdDrawIndexed-None-00469", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-00469)"},
-    {"VUID-vkCmdDrawIndexed-None-00472", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-00472)"},
+    {"VUID-vkCmdDrawIndexed-None-00472", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-00472)"},
     {"VUID-vkCmdDrawIndexed-None-01500", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-01500)"},
     {"VUID-vkCmdDrawIndexed-None-02011", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-02011)"},
-    {"VUID-vkCmdDrawIndexed-None-02012", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-02012)"},
+    {"VUID-vkCmdDrawIndexed-None-02012", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-02012)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-01853", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-01853)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-01854", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-01854)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-01855", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-01855)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndexed-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-commandBuffer-recording)"},
+    {"VUID-vkCmdDrawIndexed-filterCubic-02615", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-filterCubic-02615)"},
+    {"VUID-vkCmdDrawIndexed-filterCubicMinmax-02616", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-filterCubicMinmax-02616)"},
     {"VUID-vkCmdDrawIndexed-flags-02043", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-flags-02043)"},
     {"VUID-vkCmdDrawIndexed-indexSize-00463", "(indexSize * (firstIndex + indexCount) + offset) must be less than or equal to the size of the bound index buffer, with indexSize being based on the type specified by indexType, where the index buffer, indexType, and offset are specified via vkCmdBindIndexBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-indexSize-00463)"},
     {"VUID-vkCmdDrawIndexed-maxMultiviewInstanceIndex-00473", "If the draw is recorded in a render pass instance with multiview enabled, the maximum instance index must be less than or equal to VkPhysicalDeviceMultiviewProperties::maxMultiviewInstanceIndex. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-maxMultiviewInstanceIndex-00473)"},
@@ -2958,16 +3194,15 @@
     {"VUID-vkCmdDrawIndexedIndirect-None-00545", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-00545)"},
     {"VUID-vkCmdDrawIndexedIndirect-None-00546", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-00546)"},
     {"VUID-vkCmdDrawIndexedIndirect-None-00547", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-00547)"},
-    {"VUID-vkCmdDrawIndexedIndirect-None-00550", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-00550)"},
+    {"VUID-vkCmdDrawIndexedIndirect-None-00550", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-00550)"},
     {"VUID-vkCmdDrawIndexedIndirect-None-01503", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-01503)"},
     {"VUID-vkCmdDrawIndexedIndirect-None-02018", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-02018)"},
-    {"VUID-vkCmdDrawIndexedIndirect-None-02019", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-02019)"},
+    {"VUID-vkCmdDrawIndexedIndirect-None-02019", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-None-02019)"},
     {"VUID-vkCmdDrawIndexedIndirect-buffer-00526", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-buffer-00526)"},
     {"VUID-vkCmdDrawIndexedIndirect-buffer-01665", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-buffer-01665)"},
     {"VUID-vkCmdDrawIndexedIndirect-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-buffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-01862", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-01862)"},
-    {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-01863", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-01863)"},
-    {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-01864", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-01864)"},
+    {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-02643", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-02643)"},
     {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirect-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-commandBuffer-recording)"},
@@ -2977,6 +3212,8 @@
     {"VUID-vkCmdDrawIndexedIndirect-drawCount-00539", "If drawCount is equal to 1, (offset + sizeof(VkDrawIndexedIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-drawCount-00539)"},
     {"VUID-vkCmdDrawIndexedIndirect-drawCount-00540", "If drawCount is greater than 1, (stride {times} (drawCount - 1) + offset + sizeof(VkDrawIndexedIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-drawCount-00540)"},
     {"VUID-vkCmdDrawIndexedIndirect-drawCount-00541", "drawCount must be less than or equal to VkPhysicalDeviceLimits::maxDrawIndirectCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-drawCount-00541)"},
+    {"VUID-vkCmdDrawIndexedIndirect-filterCubic-02621", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-filterCubic-02621)"},
+    {"VUID-vkCmdDrawIndexedIndirect-filterCubicMinmax-02622", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-filterCubicMinmax-02622)"},
     {"VUID-vkCmdDrawIndexedIndirect-firstInstance-00530", "If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the VkDrawIndexedIndirectCommand structures accessed by this command must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-firstInstance-00530)"},
     {"VUID-vkCmdDrawIndexedIndirect-flags-02047", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-flags-02047)"},
     {"VUID-vkCmdDrawIndexedIndirect-maxMultiviewInstanceIndex-00551", "If the draw is recorded in a render pass instance with multiview enabled, the maximum instance index must be less than or equal to VkPhysicalDeviceMultiviewProperties::maxMultiviewInstanceIndex. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirect-maxMultiviewInstanceIndex-00551)"},
@@ -3003,8 +3240,7 @@
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-buffer-01667", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-buffer-01667)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-buffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01865", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01865)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01866", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01866)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01867", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-01867)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-02645", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-02645)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-commandBuffer-recording)"},
@@ -3027,7 +3263,7 @@
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-stride-00557", "stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndexedIndirectCommand) (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-stride-00557)"},
     {"VUID-vkCmdDrawIndexedIndirectCountAMD-subpass-00561", "The subpass index of the current render pass must be equal to the subpass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountAMD-subpass-00561)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-02020", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-02020)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-02021", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-02021)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-02021", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-02021)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03147", "For each set n that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a descriptor set must have been bound to n at VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for set n, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03147)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03148", "For each push constant that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a push constant value must have been set for VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for push constants, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03148)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03149", "Descriptors in each bound descriptor set, specified via vkCmdBindDescriptorSets, must be valid if they are statically used by the bound VkPipeline object, specified via vkCmdBindPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03149)"},
@@ -3041,13 +3277,12 @@
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03160", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03160)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03161", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03161)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03163", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03163)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03173", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03173)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountKHR-None-03173", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-None-03173)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03136", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03136)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03137", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-03137)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-buffer-parameter)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-02644", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-02644)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03165", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03165)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03166", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03166)"},
-    {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03167", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-03167)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-commandBuffer-recording)"},
@@ -3059,6 +3294,8 @@
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-countBuffer-parameter", "countBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-countBuffer-parameter)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-countBufferOffset-03141", "countBufferOffset must be a multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-countBufferOffset-03141)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-drawCount-03155", "drawCount must be less than or equal to VkPhysicalDeviceLimits::maxDrawIndirectCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-drawCount-03155)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountKHR-filterCubic-02623", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-filterCubic-02623)"},
+    {"VUID-vkCmdDrawIndexedIndirectCountKHR-filterCubicMinmax-02624", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-filterCubicMinmax-02624)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-firstInstance-03144", "If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the VkDrawIndexedIndirectCommand structures accessed by this command must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-firstInstance-03144)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-flags-02048", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-flags-02048)"},
     {"VUID-vkCmdDrawIndexedIndirectCountKHR-maxDrawCount-03143", "If maxDrawCount is greater than or equal to 1, (stride {times} (maxDrawCount - 1) + offset + sizeof(VkDrawIndexedIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndexedIndirectCountKHR-maxDrawCount-03143)"},
@@ -3081,16 +3318,15 @@
     {"VUID-vkCmdDrawIndirect-None-00493", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-00493)"},
     {"VUID-vkCmdDrawIndirect-None-00494", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-00494)"},
     {"VUID-vkCmdDrawIndirect-None-00495", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-00495)"},
-    {"VUID-vkCmdDrawIndirect-None-00498", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-00498)"},
+    {"VUID-vkCmdDrawIndirect-None-00498", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-00498)"},
     {"VUID-vkCmdDrawIndirect-None-01501", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-01501)"},
     {"VUID-vkCmdDrawIndirect-None-02013", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-02013)"},
-    {"VUID-vkCmdDrawIndirect-None-02014", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-02014)"},
+    {"VUID-vkCmdDrawIndirect-None-02014", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-None-02014)"},
     {"VUID-vkCmdDrawIndirect-buffer-00474", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-buffer-00474)"},
     {"VUID-vkCmdDrawIndirect-buffer-01660", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-buffer-01660)"},
     {"VUID-vkCmdDrawIndirect-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-buffer-parameter)"},
     {"VUID-vkCmdDrawIndirect-commandBuffer-01856", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-01856)"},
-    {"VUID-vkCmdDrawIndirect-commandBuffer-01857", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-01857)"},
-    {"VUID-vkCmdDrawIndirect-commandBuffer-01858", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-01858)"},
+    {"VUID-vkCmdDrawIndirect-commandBuffer-02640", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-02640)"},
     {"VUID-vkCmdDrawIndirect-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndirect-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndirect-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-commandBuffer-recording)"},
@@ -3100,6 +3336,8 @@
     {"VUID-vkCmdDrawIndirect-drawCount-00487", "If drawCount is equal to 1, (offset + sizeof(VkDrawIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-drawCount-00487)"},
     {"VUID-vkCmdDrawIndirect-drawCount-00488", "If drawCount is greater than 1, (stride {times} (drawCount - 1) + offset + sizeof(VkDrawIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-drawCount-00488)"},
     {"VUID-vkCmdDrawIndirect-drawCount-00489", "drawCount must be less than or equal to VkPhysicalDeviceLimits::maxDrawIndirectCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-drawCount-00489)"},
+    {"VUID-vkCmdDrawIndirect-filterCubic-02617", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-filterCubic-02617)"},
+    {"VUID-vkCmdDrawIndirect-filterCubicMinmax-02618", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-filterCubicMinmax-02618)"},
     {"VUID-vkCmdDrawIndirect-firstInstance-00478", "If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the VkDrawIndirectCommand structures accessed by this command must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-firstInstance-00478)"},
     {"VUID-vkCmdDrawIndirect-flags-02044", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-flags-02044)"},
     {"VUID-vkCmdDrawIndirect-maxMultiviewInstanceIndex-00499", "If the draw is recorded in a render pass instance with multiview enabled, the maximum instance index must be less than or equal to VkPhysicalDeviceMultiviewProperties::maxMultiviewInstanceIndex. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirect-maxMultiviewInstanceIndex-00499)"},
@@ -3120,18 +3358,19 @@
     {"VUID-vkCmdDrawIndirectByteCountEXT-None-02302", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions with ImplicitLod, Dref or Proj in their name, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02302)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-None-02303", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02303)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-None-02304", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02304)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02305", "If a VkImageView is sampled with with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02305)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02306", "If a VkImageView is sampled with with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02306)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02307", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02307)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02305", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02305)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02306", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02306)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-None-02307", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-None-02307)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02309", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02309)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02310", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02310)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02311", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02311)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02646", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-02646)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commandBuffer-recording)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-commonparent", "Both of commandBuffer, and counterBuffer must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-commonparent)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-counterBuffer-02290", "counterBuffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-counterBuffer-02290)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-counterBuffer-parameter", "counterBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-counterBuffer-parameter)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-filterCubic-02625", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-filterCubic-02625)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-filterCubicMinmax-02626", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-filterCubicMinmax-02626)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-maxMultiviewInstanceIndex-02308", "If the draw is recorded in a render pass instance with multiview enabled, the maximum instance index must be less than or equal to VkPhysicalDeviceMultiviewProperties::maxMultiviewInstanceIndex (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-maxMultiviewInstanceIndex-02308)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-renderPass-02291", "The current render pass must be compatible with the renderPass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-renderPass-02291)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-renderpass", "This command must only be called inside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-renderpass)"},
@@ -3139,7 +3378,7 @@
     {"VUID-vkCmdDrawIndirectByteCountEXT-subpass-02292", "The subpass index of the current render pass must be equal to the subpass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-subpass-02292)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-transformFeedback-02287", "VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-transformFeedback-02287)"},
     {"VUID-vkCmdDrawIndirectByteCountEXT-transformFeedbackDraw-02288", "The implementation must support VkPhysicalDeviceTransformFeedbackPropertiesEXT::transformFeedbackDraw (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-transformFeedbackDraw-02288)"},
-    {"VUID-vkCmdDrawIndirectByteCountEXT-vertexStride-02289", "vertexStride must be less than or equal to VkPhysicalDeviceLimits::maxVertexInputBindingStride (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-vertexStride-02289)"},
+    {"VUID-vkCmdDrawIndirectByteCountEXT-vertexStride-02289", "vertexStride must be greater than 0 and less than or equal to VkPhysicalDeviceLimits::maxTransformFeedbackBufferDataStride (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectByteCountEXT-vertexStride-02289)"},
     {"VUID-vkCmdDrawIndirectCountAMD-None-00509", "For each set n that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a descriptor set must have been bound to n at VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for set n, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-None-00509)"},
     {"VUID-vkCmdDrawIndirectCountAMD-None-00510", "For each push constant that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a push constant value must have been set for VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for push constants, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-None-00510)"},
     {"VUID-vkCmdDrawIndirectCountAMD-None-00511", "Descriptors in each bound descriptor set, specified via vkCmdBindDescriptorSets, must be valid if they are statically used by the bound VkPipeline object, specified via vkCmdBindPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-None-00511)"},
@@ -3158,8 +3397,7 @@
     {"VUID-vkCmdDrawIndirectCountAMD-buffer-01662", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-buffer-01662)"},
     {"VUID-vkCmdDrawIndirectCountAMD-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-buffer-parameter)"},
     {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01859", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01859)"},
-    {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01860", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01860)"},
-    {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01861", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-01861)"},
+    {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-02642", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-02642)"},
     {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndirectCountAMD-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-commandBuffer-recording)"},
@@ -3182,7 +3420,7 @@
     {"VUID-vkCmdDrawIndirectCountAMD-stride-00504", "stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndirectCommand) (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-stride-00504)"},
     {"VUID-vkCmdDrawIndirectCountAMD-subpass-00508", "The subpass index of the current render pass must be equal to the subpass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountAMD-subpass-00508)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-02015", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-02015)"},
-    {"VUID-vkCmdDrawIndirectCountKHR-None-02016", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-02016)"},
+    {"VUID-vkCmdDrawIndirectCountKHR-None-02016", "If a VkImageView is sampled with VK_FILTER_CUBIC_EXT as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-02016)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-03115", "For each set n that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a descriptor set must have been bound to n at VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for set n, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03115)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-03116", "For each push constant that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS, a push constant value must have been set for VK_PIPELINE_BIND_POINT_GRAPHICS, with a VkPipelineLayout that is compatible for push constants, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03116)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-03117", "Descriptors in each bound descriptor set, specified via vkCmdBindDescriptorSets, must be valid if they are statically used by the bound VkPipeline object, specified via vkCmdBindPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03117)"},
@@ -3196,13 +3434,12 @@
     {"VUID-vkCmdDrawIndirectCountKHR-None-03128", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03128)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-03129", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03129)"},
     {"VUID-vkCmdDrawIndirectCountKHR-None-03131", "Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03131)"},
-    {"VUID-vkCmdDrawIndirectCountKHR-None-03170", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03170)"},
+    {"VUID-vkCmdDrawIndirectCountKHR-None-03170", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-None-03170)"},
     {"VUID-vkCmdDrawIndirectCountKHR-buffer-03104", "If buffer is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-buffer-03104)"},
     {"VUID-vkCmdDrawIndirectCountKHR-buffer-03105", "buffer must have been created with the VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT bit set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-buffer-03105)"},
     {"VUID-vkCmdDrawIndirectCountKHR-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-buffer-parameter)"},
+    {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-02641", "commandBuffer must not be a protected command buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-02641)"},
     {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03133", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03133)"},
-    {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03134", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03134)"},
-    {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03135", "If commandBuffer is a protected command buffer, and any pipeline stage other than the framebuffer-space pipeline stages in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_GRAPHICS reads from or writes to any image or buffer, the image or buffer must not be a protected image or protected buffer. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-03135)"},
     {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-cmdpool)"},
     {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-parameter)"},
     {"VUID-vkCmdDrawIndirectCountKHR-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-commandBuffer-recording)"},
@@ -3214,6 +3451,8 @@
     {"VUID-vkCmdDrawIndirectCountKHR-countBuffer-03123", "The count stored in countBuffer must be less than or equal to VkPhysicalDeviceLimits::maxDrawIndirectCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-countBuffer-03123)"},
     {"VUID-vkCmdDrawIndirectCountKHR-countBuffer-parameter", "countBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-countBuffer-parameter)"},
     {"VUID-vkCmdDrawIndirectCountKHR-countBufferOffset-03109", "countBufferOffset must be a multiple of 4 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-countBufferOffset-03109)"},
+    {"VUID-vkCmdDrawIndirectCountKHR-filterCubic-02619", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubic returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-filterCubic-02619)"},
+    {"VUID-vkCmdDrawIndirectCountKHR-filterCubicMinmax-02620", "Any VkImageView being sampled with VK_FILTER_CUBIC_EXT with a reduction mode of either VK_SAMPLER_REDUCTION_MODE_MIN_EXT or VK_SAMPLER_REDUCTION_MODE_MAX_EXT as a result of this command must have a VkImageViewType and format that supports cubic filtering together with minmax filtering, as specified by VkFilterCubicImageViewImageFormatPropertiesEXT::filterCubicMinmax returned by vkGetPhysicalDeviceImageFormatProperties2 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-filterCubicMinmax-02620)"},
     {"VUID-vkCmdDrawIndirectCountKHR-firstInstance-03112", "If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the VkDrawIndirectCommand structures accessed by this command must be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-firstInstance-03112)"},
     {"VUID-vkCmdDrawIndirectCountKHR-flags-02045", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-flags-02045)"},
     {"VUID-vkCmdDrawIndirectCountKHR-maxDrawCount-03111", "If maxDrawCount is greater than or equal to 1, (stride {times} (maxDrawCount - 1) + offset + sizeof(VkDrawIndirectCommand)) must be less than or equal to the size of buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdDrawIndirectCountKHR-maxDrawCount-03111)"},
@@ -3379,13 +3618,13 @@
     {"VUID-vkCmdEndTransformFeedbackEXT-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-commandBuffer-parameter)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-commandBuffer-recording)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-commonparent", "Both of commandBuffer, and the elements of pCounterBuffers that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-commonparent)"},
+    {"VUID-vkCmdEndTransformFeedbackEXT-counterBufferCount-02608", "If counterBufferCount is not 0, and pCounterBuffers is not NULL, pCounterBuffers must be a valid pointer to an array of counterBufferCount VkBuffer handles that are either valid or VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-counterBufferCount-02608)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-firstCounterBuffer-02376", "firstCounterBuffer must be less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-firstCounterBuffer-02376)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-firstCounterBuffer-02377", "The sum of firstCounterBuffer and counterBufferCount must be less than or equal to VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackBuffers (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-firstCounterBuffer-02377)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffer-02379", "If pCounterBuffer is NULL, then pCounterBufferOffsets must also be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffer-02379)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-pCounterBufferOffsets-02378", "For each buffer handle in the array, if it is not VK_NULL_HANDLE it must reference a buffer large enough to hold 4 bytes at the corresponding offset from the pCounterBufferOffsets array (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-pCounterBufferOffsets-02378)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-pCounterBufferOffsets-parameter", "If counterBufferCount is not 0, and pCounterBufferOffsets is not NULL, pCounterBufferOffsets must be a valid pointer to an array of counterBufferCount VkDeviceSize values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-pCounterBufferOffsets-parameter)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffers-02380", "For each buffer handle in the pCounterBuffers array that is not VK_NULL_HANDLE it must have been created with a usage value containing VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffers-02380)"},
-    {"VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffers-parameter", "If counterBufferCount is not 0, and pCounterBuffers is not NULL, pCounterBuffers must be a valid pointer to an array of counterBufferCount valid VkBuffer handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffers-parameter)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-renderpass", "This command must only be called inside of a render pass instance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-renderpass)"},
     {"VUID-vkCmdEndTransformFeedbackEXT-transformFeedback-02374", "VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdEndTransformFeedbackEXT-transformFeedback-02374)"},
     {"VUID-vkCmdExecuteCommands-None-02286", "This command must not be recorded when transform feedback is active (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdExecuteCommands-None-02286)"},
@@ -3466,11 +3705,13 @@
     {"VUID-vkCmdPipelineBarrier-dstStageMask-02118", "If the task shaders feature is not enabled, dstStageMask must not contain VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-dstStageMask-02118)"},
     {"VUID-vkCmdPipelineBarrier-dstStageMask-parameter", "dstStageMask must be a valid combination of VkPipelineStageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-dstStageMask-parameter)"},
     {"VUID-vkCmdPipelineBarrier-dstStageMask-requiredbitmask", "dstStageMask must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-dstStageMask-requiredbitmask)"},
-    {"VUID-vkCmdPipelineBarrier-image-01179", "If vkCmdPipelineBarrier is called within a render pass instance, the image member of any element of pImageMemoryBarriers must be equal to one of the elements of pAttachments that the current framebuffer was created with, that is also referred to by one of the elements of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance that the current subpass was created with (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-image-01179)"},
-    {"VUID-vkCmdPipelineBarrier-oldLayout-01180", "If vkCmdPipelineBarrier is called within a render pass instance, the oldLayout and newLayout members of any element of pImageMemoryBarriers must be equal to the layout member of an element of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance that the current subpass was created with, that refers to the same image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-oldLayout-01180)"},
+    {"VUID-vkCmdPipelineBarrier-image-02635", "If vkCmdPipelineBarrier is called within a render pass instance, the image member of any element of pImageMemoryBarriers must be equal to one of the elements of pAttachments that the current framebuffer was created with, that is also referred to by one of the elements of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance or by the pDepthStencilResolveAttachment member of the VkSubpassDescriptionDepthStencilResolveKHR structure that the current subpass was created with (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-image-02635)"},
+    {"VUID-vkCmdPipelineBarrier-image-02637", "If vkCmdPipelineBarrier is called within a render pass instance, the image member of any element of pImageMemoryBarriers must be equal to one of the elements of pAttachments that the current framebuffer was created with, that is also referred to by one of the elements of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance that the current subpass was created with (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-image-02637)"},
     {"VUID-vkCmdPipelineBarrier-oldLayout-01181", "If vkCmdPipelineBarrier is called within a render pass instance, the oldLayout and newLayout members of an element of pImageMemoryBarriers must be equal (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-oldLayout-01181)"},
+    {"VUID-vkCmdPipelineBarrier-oldLayout-02636", "If vkCmdPipelineBarrier is called within a render pass instance, the oldLayout and newLayout members of any element of pImageMemoryBarriers must be equal to the layout member of an element of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance or by the pDepthStencilResolveAttachment member of the VkSubpassDescriptionDepthStencilResolveKHR structure that the current subpass was created with, that refers to the same image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-oldLayout-02636)"},
+    {"VUID-vkCmdPipelineBarrier-oldLayout-02638", "If vkCmdPipelineBarrier is called within a render pass instance, the oldLayout and newLayout members of any element of pImageMemoryBarriers must be equal to the layout member of an element of the pColorAttachments, pResolveAttachments or pDepthStencilAttachment members of the VkSubpassDescription instance that the current subpass was created with, that refers to the same image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-oldLayout-02638)"},
     {"VUID-vkCmdPipelineBarrier-pBufferMemoryBarriers-parameter", "If bufferMemoryBarrierCount is not 0, pBufferMemoryBarriers must be a valid pointer to an array of bufferMemoryBarrierCount valid VkBufferMemoryBarrier structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pBufferMemoryBarriers-parameter)"},
-    {"VUID-vkCmdPipelineBarrier-pDependencies-02285", "If vkCmdPipelineBarrier is called within a render pass instance, the render pass must have been created with at least one VkSubpassDependency instance in VkRenderPassCreateInfo::pDependencies that expresses a dependency from the current subpass to itself, and for which srcStageMask contains a subset of the bit values in VkSubpassDependency::srcStageMask, dstStageMask contains a subset of the bit values in VkSubpassDependency::dstStageMask, dependencyFlags is equal to VkSubpassDependency::dependencyFlags, srcAccessMask member of each each element of pMemoryBarriers and pImageMemoryBarriers contains a subset of the bit values in VkSubpassDependency::srcAccessMask, and dstAccessMask member of each element of pMemoryBarriers and pImageMemoryBarriers contains a subset of the bit values in VkSubpassDependency::dstAccessMask (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pDependencies-02285)"},
+    {"VUID-vkCmdPipelineBarrier-pDependencies-02285", "If vkCmdPipelineBarrier is called within a render pass instance, the render pass must have been created with at least one VkSubpassDependency instance in VkRenderPassCreateInfo::pDependencies that expresses a dependency from the current subpass to itself, and for which srcStageMask contains a subset of the bit values in VkSubpassDependency::srcStageMask, dstStageMask contains a subset of the bit values in VkSubpassDependency::dstStageMask, dependencyFlags is equal to VkSubpassDependency::dependencyFlags, srcAccessMask member of each element of pMemoryBarriers and pImageMemoryBarriers contains a subset of the bit values in VkSubpassDependency::srcAccessMask, and dstAccessMask member of each element of pMemoryBarriers and pImageMemoryBarriers contains a subset of the bit values in VkSubpassDependency::dstAccessMask (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pDependencies-02285)"},
     {"VUID-vkCmdPipelineBarrier-pImageMemoryBarriers-parameter", "If imageMemoryBarrierCount is not 0, pImageMemoryBarriers must be a valid pointer to an array of imageMemoryBarrierCount valid VkImageMemoryBarrier structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pImageMemoryBarriers-parameter)"},
     {"VUID-vkCmdPipelineBarrier-pMemoryBarriers-01184", "Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not have any access flag included in its srcAccessMask member if that bit is not supported by any of the pipeline stages in srcStageMask, as specified in the table of supported access types. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pMemoryBarriers-01184)"},
     {"VUID-vkCmdPipelineBarrier-pMemoryBarriers-01185", "Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not have any access flag included in its dstAccessMask member if that bit is not supported by any of the pipeline stages in dstStageMask, as specified in the table of supported access types. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdPipelineBarrier-pMemoryBarriers-01185)"},
@@ -3563,6 +3804,7 @@
     {"VUID-vkCmdResolveImage-dstImage-00258", "If dstImage is non-sparse then it must be bound completely and contiguously to a single VkDeviceMemory object (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImage-00258)"},
     {"VUID-vkCmdResolveImage-dstImage-00259", "dstImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImage-00259)"},
     {"VUID-vkCmdResolveImage-dstImage-02003", "The format features of dstImage must contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImage-02003)"},
+    {"VUID-vkCmdResolveImage-dstImage-02546", "dstImage and srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImage-02546)"},
     {"VUID-vkCmdResolveImage-dstImage-parameter", "dstImage must be a valid VkImage handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImage-parameter)"},
     {"VUID-vkCmdResolveImage-dstImageLayout-00262", "dstImageLayout must specify the layout of the image subresources of dstImage specified in pRegions at the time this command is executed on a VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImageLayout-00262)"},
     {"VUID-vkCmdResolveImage-dstImageLayout-00263", "dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdResolveImage-dstImageLayout-00263)"},
@@ -3610,11 +3852,9 @@
     {"VUID-vkCmdSetDepthBounds-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-commandBuffer-parameter)"},
     {"VUID-vkCmdSetDepthBounds-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-commandBuffer-recording)"},
     {"VUID-vkCmdSetDepthBounds-maxDepthBounds-00601", "Unless the VK_EXT_depth_range_unrestricted extension is enabled maxDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-maxDepthBounds-00601)"},
-    {"VUID-vkCmdSetDepthBounds-maxDepthBounds-00601[(VK_EXT_depth_range_unrestricted)]", "Unless the VK_EXT_depth_range_unrestricted extension is enabled maxDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-maxDepthBounds-00601)"},
-    {"VUID-vkCmdSetDepthBounds-maxDepthBounds-00601[!(VK_EXT_depth_range_unrestricted)]", "maxDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-maxDepthBounds-00601)"},
+    {"VUID-vkCmdSetDepthBounds-maxDepthBounds-02509", "maxDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-maxDepthBounds-02509)"},
     {"VUID-vkCmdSetDepthBounds-minDepthBounds-00600", "Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-minDepthBounds-00600)"},
-    {"VUID-vkCmdSetDepthBounds-minDepthBounds-00600[(VK_EXT_depth_range_unrestricted)]", "Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-minDepthBounds-00600)"},
-    {"VUID-vkCmdSetDepthBounds-minDepthBounds-00600[!(VK_EXT_depth_range_unrestricted)]", "minDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-minDepthBounds-00600)"},
+    {"VUID-vkCmdSetDepthBounds-minDepthBounds-02508", "minDepthBounds must be between 0.0 and 1.0, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDepthBounds-minDepthBounds-02508)"},
     {"VUID-vkCmdSetDeviceMask-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, compute, or transfer operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDeviceMask-commandBuffer-cmdpool)"},
     {"VUID-vkCmdSetDeviceMask-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDeviceMask-commandBuffer-parameter)"},
     {"VUID-vkCmdSetDeviceMask-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetDeviceMask-commandBuffer-recording)"},
@@ -3732,13 +3972,47 @@
     {"VUID-vkCmdSetViewportWScalingNV-firstViewport-01324", "The sum of firstViewport and viewportCount must be between 1 and VkPhysicalDeviceLimits::maxViewports, inclusive (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetViewportWScalingNV-firstViewport-01324)"},
     {"VUID-vkCmdSetViewportWScalingNV-pViewportWScalings-parameter", "pViewportWScalings must be a valid pointer to an array of viewportCount VkViewportWScalingNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetViewportWScalingNV-pViewportWScalings-parameter)"},
     {"VUID-vkCmdSetViewportWScalingNV-viewportCount-arraylength", "viewportCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdSetViewportWScalingNV-viewportCount-arraylength)"},
-    {"VUID-vkCmdTraceRaysNVX-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-commandBuffer-cmdpool)"},
-    {"VUID-vkCmdTraceRaysNVX-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-commandBuffer-parameter)"},
-    {"VUID-vkCmdTraceRaysNVX-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-commandBuffer-recording)"},
-    {"VUID-vkCmdTraceRaysNVX-commonparent", "Each of commandBuffer, hitShaderBindingTableBuffer, missShaderBindingTableBuffer, and raygenShaderBindingTableBuffer must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-commonparent)"},
-    {"VUID-vkCmdTraceRaysNVX-hitShaderBindingTableBuffer-parameter", "hitShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-hitShaderBindingTableBuffer-parameter)"},
-    {"VUID-vkCmdTraceRaysNVX-missShaderBindingTableBuffer-parameter", "missShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-missShaderBindingTableBuffer-parameter)"},
-    {"VUID-vkCmdTraceRaysNVX-raygenShaderBindingTableBuffer-parameter", "raygenShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNVX-raygenShaderBindingTableBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-None-02472", "For each set n that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, a descriptor set must have been bound to n at VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, with a VkPipelineLayout that is compatible for set n, with the VkPipelineLayout used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02472)"},
+    {"VUID-vkCmdTraceRaysNV-None-02473", "Descriptors in each bound descriptor set, specified via vkCmdBindDescriptorSets, must be valid if they are statically used by the bound VkPipeline object, specified via vkCmdBindPipeline (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02473)"},
+    {"VUID-vkCmdTraceRaysNV-None-02474", "A valid ray tracing pipeline must be bound to the current command buffer with VK_PIPELINE_BIND_POINT_RAY_TRACING_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02474)"},
+    {"VUID-vkCmdTraceRaysNV-None-02475", "For each push constant that is statically used by the VkPipeline bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, a push constant value must have been set for VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, with a VkPipelineLayout that is compatible for push constants with the one used to create the current VkPipeline, as described in Pipeline Layout Compatibility (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02475)"},
+    {"VUID-vkCmdTraceRaysNV-None-02476", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV uses unnormalized coordinates, it must not be used to sample from any VkImage with a VkImageView of the type VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, VK_IMAGE_VIEW_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02476)"},
+    {"VUID-vkCmdTraceRaysNV-None-02477", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions with ImplicitLod, Dref or Proj in their name, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02477)"},
+    {"VUID-vkCmdTraceRaysNV-None-02478", "If any VkSampler object that is accessed from a shader by the VkPipeline bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV uses unnormalized coordinates, it must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample* instructions that includes a LOD bias or any offset values, in any shader stage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02478)"},
+    {"VUID-vkCmdTraceRaysNV-None-02479", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV accesses a uniform buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02479)"},
+    {"VUID-vkCmdTraceRaysNV-None-02480", "If the robust buffer access feature is not enabled, and any shader stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV accesses a storage buffer, it must not access values outside of the range of that buffer specified in the bound descriptor set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02480)"},
+    {"VUID-vkCmdTraceRaysNV-None-02481", "If a VkImageView is sampled with VK_FILTER_LINEAR as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02481)"},
+    {"VUID-vkCmdTraceRaysNV-None-02482", "If a VkImageView is sampled with VK_FILTER_CUBIC_IMG as a result of this command, then the image view's format features must contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02482)"},
+    {"VUID-vkCmdTraceRaysNV-None-02483", "Any VkImageView being sampled with VK_FILTER_CUBIC_IMG as a result of this command must not have a VkImageViewType of VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_CUBE, or VK_IMAGE_VIEW_TYPE_CUBE_ARRAY (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-None-02483)"},
+    {"VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02461", "callableShaderBindingOffset must be less than the size of callableShaderBindingTableBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02461)"},
+    {"VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02462", "callableShaderBindingOffset must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupBaseAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-callableShaderBindingOffset-02462)"},
+    {"VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02465", "callableShaderBindingStride must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupHandleSize (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02465)"},
+    {"VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02468", "callableShaderBindingStride must be a less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxShaderGroupStride (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-callableShaderBindingStride-02468)"},
+    {"VUID-vkCmdTraceRaysNV-callableShaderBindingTableBuffer-parameter", "If callableShaderBindingTableBuffer is not VK_NULL_HANDLE, callableShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-callableShaderBindingTableBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-02484", "If commandBuffer is an unprotected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV reads from or writes to any image or buffer, that image or buffer must not be a protected image or protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-02484)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-02485", "If commandBuffer is a protected command buffer, and any pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV writes to any image or buffer, that image or buffer must not be an unprotected image or unprotected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-02485)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-02486", "If commandBuffer is a protected command buffer, and any pipeline stage other than the ray tracing pipeline stage in the VkPipeline object bound to VK_PIPELINE_BIND_POINT_RAY_TRACING_NV reads from any image or buffer, the image or buffer must not be a protected image or protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-02486)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-cmdpool)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commandBuffer-recording)"},
+    {"VUID-vkCmdTraceRaysNV-commonparent", "Each of callableShaderBindingTableBuffer, commandBuffer, hitShaderBindingTableBuffer, missShaderBindingTableBuffer, and raygenShaderBindingTableBuffer that are valid handles must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-commonparent)"},
+    {"VUID-vkCmdTraceRaysNV-depth-02471", "depth must be less than or equal to VkPhysicalDeviceLimits::maxComputeWorkGroupCount[2] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-depth-02471)"},
+    {"VUID-vkCmdTraceRaysNV-flags-02487", "Any VkImage created with a VkImageCreateInfo::flags containing VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV sampled as a result of this command must only be sampled using a VkSamplerAddressMode of VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-flags-02487)"},
+    {"VUID-vkCmdTraceRaysNV-height-02470", "height must be less than or equal to VkPhysicalDeviceLimits::maxComputeWorkGroupCount[1] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-height-02470)"},
+    {"VUID-vkCmdTraceRaysNV-hitShaderBindingOffset-02459", "hitShaderBindingOffset must be less than the size of hitShaderBindingTableBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-hitShaderBindingOffset-02459)"},
+    {"VUID-vkCmdTraceRaysNV-hitShaderBindingOffset-02460", "hitShaderBindingOffset must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupBaseAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-hitShaderBindingOffset-02460)"},
+    {"VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02464", "hitShaderBindingStride must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupHandleSize (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02464)"},
+    {"VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02467", "hitShaderBindingStride must be a less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxShaderGroupStride (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-hitShaderBindingStride-02467)"},
+    {"VUID-vkCmdTraceRaysNV-hitShaderBindingTableBuffer-parameter", "If hitShaderBindingTableBuffer is not VK_NULL_HANDLE, hitShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-hitShaderBindingTableBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02457", "missShaderBindingOffset must be less than the size of missShaderBindingTableBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02457)"},
+    {"VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02458", "missShaderBindingOffset must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupBaseAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-missShaderBindingOffset-02458)"},
+    {"VUID-vkCmdTraceRaysNV-missShaderBindingStride-02463", "missShaderBindingStride must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupHandleSize (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-missShaderBindingStride-02463)"},
+    {"VUID-vkCmdTraceRaysNV-missShaderBindingStride-02466", "missShaderBindingStride must be a less than or equal to VkPhysicalDeviceRayTracingPropertiesNV::maxShaderGroupStride (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-missShaderBindingStride-02466)"},
+    {"VUID-vkCmdTraceRaysNV-missShaderBindingTableBuffer-parameter", "If missShaderBindingTableBuffer is not VK_NULL_HANDLE, missShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-missShaderBindingTableBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-raygenShaderBindingOffset-02455", "raygenShaderBindingOffset must be less than the size of raygenShaderBindingTableBuffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-raygenShaderBindingOffset-02455)"},
+    {"VUID-vkCmdTraceRaysNV-raygenShaderBindingOffset-02456", "raygenShaderBindingOffset must be a multiple of VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupBaseAlignment (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-raygenShaderBindingOffset-02456)"},
+    {"VUID-vkCmdTraceRaysNV-raygenShaderBindingTableBuffer-parameter", "raygenShaderBindingTableBuffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-raygenShaderBindingTableBuffer-parameter)"},
+    {"VUID-vkCmdTraceRaysNV-width-02469", "width must be less than or equal to VkPhysicalDeviceLimits::maxComputeWorkGroupCount[0] (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdTraceRaysNV-width-02469)"},
     {"VUID-vkCmdUpdateBuffer-commandBuffer-01813", "If commandBuffer is an unprotected command buffer, then dstBuffer must not be a protected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdUpdateBuffer-commandBuffer-01813)"},
     {"VUID-vkCmdUpdateBuffer-commandBuffer-01814", "If commandBuffer is a protected command buffer, then dstBuffer must not be an unprotected buffer (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdUpdateBuffer-commandBuffer-01814)"},
     {"VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support transfer, graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool)"},
@@ -3783,14 +4057,18 @@
     {"VUID-vkCmdWaitEvents-srcStageMask-02112", "If the task shaders feature is not enabled, srcStageMask must not contain VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWaitEvents-srcStageMask-02112)"},
     {"VUID-vkCmdWaitEvents-srcStageMask-parameter", "srcStageMask must be a valid combination of VkPipelineStageFlagBits values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWaitEvents-srcStageMask-parameter)"},
     {"VUID-vkCmdWaitEvents-srcStageMask-requiredbitmask", "srcStageMask must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWaitEvents-srcStageMask-requiredbitmask)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-accelerationStructure-parameter)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-cmdpool)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-parameter)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commandBuffer-recording)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commonparent", "Each of accelerationStructure, commandBuffer, and queryPool must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-commonparent)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryPool-parameter", "queryPool must be a valid VkQueryPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryPool-parameter)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryType-02242", "queryType must be VK_QUERY_TYPE_COMPACTED_SIZE_NVX (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryType-02242)"},
-    {"VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryType-parameter", "queryType must be a valid VkQueryType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructurePropertiesNVX-queryType-parameter)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-accelerationStructureCount-arraylength", "accelerationStructureCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-accelerationStructureCount-arraylength)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-accelerationStructures-02495", "All acceleration structures in accelerationStructures must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV if queryType is VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-accelerationStructures-02495)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-cmdpool)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-parameter)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commandBuffer-recording)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commonparent", "Each of commandBuffer, queryPool, and the elements of pAccelerationStructures must have been created, allocated, or retrieved from the same VkDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-commonparent)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-pAccelerationStructures-parameter", "pAccelerationStructures must be a valid pointer to an array of accelerationStructureCount valid VkAccelerationStructureNV handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-pAccelerationStructures-parameter)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-02493", "queryPool must have been created with a queryType matching queryType (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-02493)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-02494", "The queries identified by queryPool and firstQuery must be unavailable (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-02494)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-parameter", "queryPool must be a valid VkQueryPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-parameter)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryType-02242", "queryType must be VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryType-02242)"},
+    {"VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryType-parameter", "queryType must be a valid VkQueryType value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryType-parameter)"},
     {"VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-cmdpool", "The VkCommandPool that commandBuffer was allocated from must support transfer, graphics, or compute operations (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-cmdpool)"},
     {"VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-parameter", "commandBuffer must be a valid VkCommandBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-parameter)"},
     {"VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-recording", "commandBuffer must be in the recording state (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteBufferMarkerAMD-commandBuffer-recording)"},
@@ -3812,15 +4090,15 @@
     {"VUID-vkCmdWriteTimestamp-queryPool-01416", "queryPool must have been created with a queryType of VK_QUERY_TYPE_TIMESTAMP (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteTimestamp-queryPool-01416)"},
     {"VUID-vkCmdWriteTimestamp-queryPool-parameter", "queryPool must be a valid VkQueryPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteTimestamp-queryPool-parameter)"},
     {"VUID-vkCmdWriteTimestamp-timestampValidBits-00829", "The command pool's queue family must support a non-zero timestampValidBits (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCmdWriteTimestamp-timestampValidBits-00829)"},
-    {"VUID-vkCompileDeferredNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNVX-device-parameter)"},
-    {"VUID-vkCompileDeferredNVX-pipeline-02237", "pipeline must have been created with VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNVX-pipeline-02237)"},
-    {"VUID-vkCompileDeferredNVX-pipeline-parameter", "pipeline must be a valid VkPipeline handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNVX-pipeline-parameter)"},
-    {"VUID-vkCompileDeferredNVX-pipeline-parent", "pipeline must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNVX-pipeline-parent)"},
-    {"VUID-vkCompileDeferredNVX-shader-02238", "shader must not have been called as a deferred compile before. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNVX-shader-02238)"},
-    {"VUID-vkCreateAccelerationStructureNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNVX-device-parameter)"},
-    {"VUID-vkCreateAccelerationStructureNVX-pAccelerationStructure-parameter", "pAccelerationStructure must be a valid pointer to a VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNVX-pAccelerationStructure-parameter)"},
-    {"VUID-vkCreateAccelerationStructureNVX-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNVX-pAllocator-parameter)"},
-    {"VUID-vkCreateAccelerationStructureNVX-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkAccelerationStructureCreateInfoNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNVX-pCreateInfo-parameter)"},
+    {"VUID-vkCompileDeferredNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNV-device-parameter)"},
+    {"VUID-vkCompileDeferredNV-pipeline-02237", "pipeline must have been created with VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNV-pipeline-02237)"},
+    {"VUID-vkCompileDeferredNV-pipeline-parameter", "pipeline must be a valid VkPipeline handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNV-pipeline-parameter)"},
+    {"VUID-vkCompileDeferredNV-pipeline-parent", "pipeline must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNV-pipeline-parent)"},
+    {"VUID-vkCompileDeferredNV-shader-02238", "shader must not have been called as a deferred compile before (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCompileDeferredNV-shader-02238)"},
+    {"VUID-vkCreateAccelerationStructureNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNV-device-parameter)"},
+    {"VUID-vkCreateAccelerationStructureNV-pAccelerationStructure-parameter", "pAccelerationStructure must be a valid pointer to a VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNV-pAccelerationStructure-parameter)"},
+    {"VUID-vkCreateAccelerationStructureNV-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNV-pAllocator-parameter)"},
+    {"VUID-vkCreateAccelerationStructureNV-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkAccelerationStructureCreateInfoNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAccelerationStructureNV-pCreateInfo-parameter)"},
     {"VUID-vkCreateAndroidSurfaceKHR-instance-parameter", "instance must be a valid VkInstance handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAndroidSurfaceKHR-instance-parameter)"},
     {"VUID-vkCreateAndroidSurfaceKHR-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAndroidSurfaceKHR-pAllocator-parameter)"},
     {"VUID-vkCreateAndroidSurfaceKHR-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkAndroidSurfaceCreateInfoKHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateAndroidSurfaceKHR-pCreateInfo-parameter)"},
@@ -3932,10 +4210,10 @@
     {"VUID-vkCreateMacOSSurfaceMVK-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMacOSSurfaceMVK-pAllocator-parameter)"},
     {"VUID-vkCreateMacOSSurfaceMVK-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkMacOSSurfaceCreateInfoMVK structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMacOSSurfaceMVK-pCreateInfo-parameter)"},
     {"VUID-vkCreateMacOSSurfaceMVK-pSurface-parameter", "pSurface must be a valid pointer to a VkSurfaceKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMacOSSurfaceMVK-pSurface-parameter)"},
-    {"VUID-vkCreateMirSurfaceKHR-instance-parameter", "instance must be a valid VkInstance handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMirSurfaceKHR-instance-parameter)"},
-    {"VUID-vkCreateMirSurfaceKHR-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMirSurfaceKHR-pAllocator-parameter)"},
-    {"VUID-vkCreateMirSurfaceKHR-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkMirSurfaceCreateInfoKHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMirSurfaceKHR-pCreateInfo-parameter)"},
-    {"VUID-vkCreateMirSurfaceKHR-pSurface-parameter", "pSurface must be a valid pointer to a VkSurfaceKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMirSurfaceKHR-pSurface-parameter)"},
+    {"VUID-vkCreateMetalSurfaceEXT-instance-parameter", "instance must be a valid VkInstance handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMetalSurfaceEXT-instance-parameter)"},
+    {"VUID-vkCreateMetalSurfaceEXT-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMetalSurfaceEXT-pAllocator-parameter)"},
+    {"VUID-vkCreateMetalSurfaceEXT-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkMetalSurfaceCreateInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMetalSurfaceEXT-pCreateInfo-parameter)"},
+    {"VUID-vkCreateMetalSurfaceEXT-pSurface-parameter", "pSurface must be a valid pointer to a VkSurfaceKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateMetalSurfaceEXT-pSurface-parameter)"},
     {"VUID-vkCreateObjectTableNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateObjectTableNVX-device-parameter)"},
     {"VUID-vkCreateObjectTableNVX-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateObjectTableNVX-pAllocator-parameter)"},
     {"VUID-vkCreateObjectTableNVX-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkObjectTableCreateInfoNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateObjectTableNVX-pCreateInfo-parameter)"},
@@ -3952,13 +4230,15 @@
     {"VUID-vkCreateQueryPool-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateQueryPool-pAllocator-parameter)"},
     {"VUID-vkCreateQueryPool-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkQueryPoolCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateQueryPool-pCreateInfo-parameter)"},
     {"VUID-vkCreateQueryPool-pQueryPool-parameter", "pQueryPool must be a valid pointer to a VkQueryPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateQueryPool-pQueryPool-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-createInfoCount-arraylength", "createInfoCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-createInfoCount-arraylength)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-device-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-pAllocator-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-pCreateInfos-parameter", "pCreateInfos must be a valid pointer to an array of createInfoCount valid VkRaytracingPipelineCreateInfoNVX structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-pCreateInfos-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-pPipelines-parameter", "pPipelines must be a valid pointer to an array of createInfoCount VkPipeline handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-pPipelines-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-pipelineCache-parameter", "If pipelineCache is not VK_NULL_HANDLE, pipelineCache must be a valid VkPipelineCache handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-pipelineCache-parameter)"},
-    {"VUID-vkCreateRaytracingPipelinesNVX-pipelineCache-parent", "If pipelineCache is a valid handle, it must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRaytracingPipelinesNVX-pipelineCache-parent)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-createInfoCount-arraylength", "createInfoCount must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-createInfoCount-arraylength)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-device-parameter)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-flags-02402", "If the flags member of any element of pCreateInfos contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, and the basePipelineIndex member of that same element is not -1, basePipelineIndex must be less than the index into pCreateInfos that corresponds to that element (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-flags-02402)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-flags-02403", "If the flags member of any element of pCreateInfos contains the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag, the base pipeline must have been created with the VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT flag set (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-flags-02403)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-pAllocator-parameter)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-pCreateInfos-parameter", "pCreateInfos must be a valid pointer to an array of createInfoCount valid VkRayTracingPipelineCreateInfoNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-pCreateInfos-parameter)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-pPipelines-parameter", "pPipelines must be a valid pointer to an array of createInfoCount VkPipeline handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-pPipelines-parameter)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-pipelineCache-parameter", "If pipelineCache is not VK_NULL_HANDLE, pipelineCache must be a valid VkPipelineCache handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-pipelineCache-parameter)"},
+    {"VUID-vkCreateRayTracingPipelinesNV-pipelineCache-parent", "If pipelineCache is a valid handle, it must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRayTracingPipelinesNV-pipelineCache-parent)"},
     {"VUID-vkCreateRenderPass-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRenderPass-device-parameter)"},
     {"VUID-vkCreateRenderPass-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRenderPass-pAllocator-parameter)"},
     {"VUID-vkCreateRenderPass-pCreateInfo-parameter", "pCreateInfo must be a valid pointer to a valid VkRenderPassCreateInfo structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateRenderPass-pCreateInfo-parameter)"},
@@ -4029,10 +4309,13 @@
     {"VUID-vkDebugReportMessageEXT-objectType-parameter", "objectType must be a valid VkDebugReportObjectTypeEXT value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDebugReportMessageEXT-objectType-parameter)"},
     {"VUID-vkDebugReportMessageEXT-pLayerPrefix-parameter", "pLayerPrefix must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDebugReportMessageEXT-pLayerPrefix-parameter)"},
     {"VUID-vkDebugReportMessageEXT-pMessage-parameter", "pMessage must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDebugReportMessageEXT-pMessage-parameter)"},
-    {"VUID-vkDestroyAccelerationStructureNVX-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNVX-accelerationStructure-parameter)"},
-    {"VUID-vkDestroyAccelerationStructureNVX-accelerationStructure-parent", "accelerationStructure must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNVX-accelerationStructure-parent)"},
-    {"VUID-vkDestroyAccelerationStructureNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNVX-device-parameter)"},
-    {"VUID-vkDestroyAccelerationStructureNVX-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNVX-pAllocator-parameter)"},
+    {"VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02442", "All submitted commands that refer to accelerationStructure must have completed execution (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02442)"},
+    {"VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02443", "If VkAllocationCallbacks were provided when accelerationStructure was created, a compatible set of callbacks must be provided here (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02443)"},
+    {"VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02444", "If no VkAllocationCallbacks were provided when accelerationStructure was created, pAllocator must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-accelerationStructure-02444)"},
+    {"VUID-vkDestroyAccelerationStructureNV-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-accelerationStructure-parameter)"},
+    {"VUID-vkDestroyAccelerationStructureNV-accelerationStructure-parent", "accelerationStructure must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-accelerationStructure-parent)"},
+    {"VUID-vkDestroyAccelerationStructureNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-device-parameter)"},
+    {"VUID-vkDestroyAccelerationStructureNV-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyAccelerationStructureNV-pAllocator-parameter)"},
     {"VUID-vkDestroyBuffer-buffer-00922", "All submitted commands that refer to buffer, either directly or via a VkBufferView, must have completed execution (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyBuffer-buffer-00922)"},
     {"VUID-vkDestroyBuffer-buffer-00923", "If VkAllocationCallbacks were provided when buffer was created, a compatible set of callbacks must be provided here (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyBuffer-buffer-00923)"},
     {"VUID-vkDestroyBuffer-buffer-00924", "If no VkAllocationCallbacks were provided when buffer was created, pAllocator must be NULL (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyBuffer-buffer-00924)"},
@@ -4276,22 +4559,23 @@
     {"VUID-vkFreeMemory-memory-parameter", "If memory is not VK_NULL_HANDLE, memory must be a valid VkDeviceMemory handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkFreeMemory-memory-parameter)"},
     {"VUID-vkFreeMemory-memory-parent", "If memory is a valid handle, it must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkFreeMemory-memory-parent)"},
     {"VUID-vkFreeMemory-pAllocator-parameter", "If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkFreeMemory-pAllocator-parameter)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNVX handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-accelerationStructure-parameter)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-accelerationStructure-parent", "accelerationStructure must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-accelerationStructure-parent)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-dataSize-02240", "dataSize must be large enough to contain the result of the query, as described above (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-dataSize-02240)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-dataSize-arraylength", "dataSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-dataSize-arraylength)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-device-parameter)"},
-    {"VUID-vkGetAccelerationStructureHandleNVX-pData-parameter", "pData must be a valid pointer to an array of dataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNVX-pData-parameter)"},
-    {"VUID-vkGetAccelerationStructureMemoryRequirementsNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNVX-device-parameter)"},
-    {"VUID-vkGetAccelerationStructureMemoryRequirementsNVX-pInfo-parameter", "pInfo must be a valid pointer to a valid VkAccelerationStructureMemoryRequirementsInfoNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNVX-pInfo-parameter)"},
-    {"VUID-vkGetAccelerationStructureMemoryRequirementsNVX-pMemoryRequirements-parameter", "pMemoryRequirements must be a valid pointer to a VkMemoryRequirements2KHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNVX-pMemoryRequirements-parameter)"},
-    {"VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-device-parameter)"},
-    {"VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-pInfo-parameter", "pInfo must be a valid pointer to a valid VkAccelerationStructureMemoryRequirementsInfoNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-pInfo-parameter)"},
-    {"VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-pMemoryRequirements-parameter", "pMemoryRequirements must be a valid pointer to a VkMemoryRequirements2KHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureScratchMemoryRequirementsNVX-pMemoryRequirements-parameter)"},
-    {"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884", "buffer must be a valid Android hardware buffer object with at least one of the AHARDWAREBUFFER_USAGE_GPU_* usage flags. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-parameter", "accelerationStructure must be a valid VkAccelerationStructureNV handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-parameter)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-parent", "accelerationStructure must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-accelerationStructure-parent)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-dataSize-02240", "dataSize must be large enough to contain the result of the query, as described above (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-dataSize-02240)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-dataSize-arraylength", "dataSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-dataSize-arraylength)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-device-parameter)"},
+    {"VUID-vkGetAccelerationStructureHandleNV-pData-parameter", "pData must be a valid pointer to an array of dataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureHandleNV-pData-parameter)"},
+    {"VUID-vkGetAccelerationStructureMemoryRequirementsNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNV-device-parameter)"},
+    {"VUID-vkGetAccelerationStructureMemoryRequirementsNV-pInfo-parameter", "pInfo must be a valid pointer to a valid VkAccelerationStructureMemoryRequirementsInfoNV structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNV-pInfo-parameter)"},
+    {"VUID-vkGetAccelerationStructureMemoryRequirementsNV-pMemoryRequirements-parameter", "pMemoryRequirements must be a valid pointer to a VkMemoryRequirements2KHR structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAccelerationStructureMemoryRequirementsNV-pMemoryRequirements-parameter)"},
+    {"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884", "buffer must be a valid Android hardware buffer object with at least one of the AHARDWAREBUFFER_USAGE_GPU_* flags in its AHardwareBuffer_Desc::usage (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884)"},
     {"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-parameter", "buffer must be a valid pointer to a valid AHardwareBuffer value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-parameter)"},
     {"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAndroidHardwareBufferPropertiesANDROID-device-parameter)"},
     {"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-pProperties-parameter", "pProperties must be a valid pointer to a VkAndroidHardwareBufferPropertiesANDROID structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetAndroidHardwareBufferPropertiesANDROID-pProperties-parameter)"},
+    {"VUID-vkGetBufferDeviceAddressEXT-None-02598", "The bufferDeviceAddress feature must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferDeviceAddressEXT-None-02598)"},
+    {"VUID-vkGetBufferDeviceAddressEXT-device-02599", "If device was created with multiple physical devices, then the bufferDeviceAddressMultiDevice feature must be enabled (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferDeviceAddressEXT-device-02599)"},
+    {"VUID-vkGetBufferDeviceAddressEXT-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferDeviceAddressEXT-device-parameter)"},
+    {"VUID-vkGetBufferDeviceAddressEXT-pInfo-parameter", "pInfo must be a valid pointer to a valid VkBufferDeviceAddressInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferDeviceAddressEXT-pInfo-parameter)"},
     {"VUID-vkGetBufferMemoryRequirements-buffer-parameter", "buffer must be a valid VkBuffer handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferMemoryRequirements-buffer-parameter)"},
     {"VUID-vkGetBufferMemoryRequirements-buffer-parent", "buffer must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferMemoryRequirements-buffer-parent)"},
     {"VUID-vkGetBufferMemoryRequirements-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetBufferMemoryRequirements-device-parameter)"},
@@ -4400,6 +4684,8 @@
     {"VUID-vkGetImageSubresourceLayout-pLayout-parameter", "pLayout must be a valid pointer to a VkSubresourceLayout structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetImageSubresourceLayout-pLayout-parameter)"},
     {"VUID-vkGetImageSubresourceLayout-pSubresource-parameter", "pSubresource must be a valid pointer to a valid VkImageSubresource structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetImageSubresourceLayout-pSubresource-parameter)"},
     {"VUID-vkGetImageSubresourceLayout-tiling-02271", "If the tiling of the image is  VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, then the aspectMask  member of pSubresource must be  VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT and the index i  must be less than the  drmFormatModifierPlaneCount  associated with the image's format and drmFormatModifier. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetImageSubresourceLayout-tiling-02271)"},
+    {"VUID-vkGetImageViewHandleNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetImageViewHandleNVX-device-parameter)"},
+    {"VUID-vkGetImageViewHandleNVX-pInfo-parameter", "pInfo must be a valid pointer to a valid VkImageViewHandleInfoNVX structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetImageViewHandleNVX-pInfo-parameter)"},
     {"VUID-vkGetInstanceProcAddr-instance-parameter", "If instance is not NULL, instance must be a valid VkInstance handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetInstanceProcAddr-instance-parameter)"},
     {"VUID-vkGetInstanceProcAddr-pName-parameter", "pName must be a null-terminated UTF-8 string (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetInstanceProcAddr-pName-parameter)"},
     {"VUID-vkGetMemoryAndroidHardwareBufferANDROID-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetMemoryAndroidHardwareBufferANDROID-device-parameter)"},
@@ -4443,6 +4729,9 @@
     {"VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-pTimeDomainCount-parameter", "pTimeDomainCount must be a valid pointer to a uint32_t value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-pTimeDomainCount-parameter)"},
     {"VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-pTimeDomains-parameter", "If the value referenced by pTimeDomainCount is not 0, and pTimeDomains is not NULL, pTimeDomains must be a valid pointer to an array of pTimeDomainCount VkTimeDomainEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-pTimeDomains-parameter)"},
     {"VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCalibrateableTimeDomainsEXT-physicalDevice-parameter)"},
+    {"VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-pProperties-parameter", "If the value referenced by pPropertyCount is not 0, and pProperties is not NULL, pProperties must be a valid pointer to an array of pPropertyCount VkCooperativeMatrixPropertiesNV structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-pProperties-parameter)"},
+    {"VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-pPropertyCount-parameter", "pPropertyCount must be a valid pointer to a uint32_t value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-pPropertyCount-parameter)"},
+    {"VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceCooperativeMatrixPropertiesNV-physicalDevice-parameter)"},
     {"VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-pProperties-parameter", "If the value referenced by pPropertyCount is not 0, and pProperties is not NULL, pProperties must be a valid pointer to an array of pPropertyCount VkDisplayPlaneProperties2KHR structures (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-pProperties-parameter)"},
     {"VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-pPropertyCount-parameter", "pPropertyCount must be a valid pointer to a uint32_t value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-pPropertyCount-parameter)"},
     {"VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceDisplayPlaneProperties2KHR-physicalDevice-parameter)"},
@@ -4503,9 +4792,6 @@
     {"VUID-vkGetPhysicalDeviceMemoryProperties-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMemoryProperties-physicalDevice-parameter)"},
     {"VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter", "pMemoryProperties must be a valid pointer to a VkPhysicalDeviceMemoryProperties2 structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter)"},
     {"VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter)"},
-    {"VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-connection-parameter", "connection must be a valid pointer to a MirConnection value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-connection-parameter)"},
-    {"VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-physicalDevice-parameter)"},
-    {"VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-queueFamilyIndex-01265", "queueFamilyIndex must be less than pQueueFamilyPropertyCount returned by vkGetPhysicalDeviceQueueFamilyProperties for the given physicalDevice (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMirPresentationSupportKHR-queueFamilyIndex-01265)"},
     {"VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-pMultisampleProperties-parameter", "pMultisampleProperties must be a valid pointer to a VkMultisamplePropertiesEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-pMultisampleProperties-parameter)"},
     {"VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-physicalDevice-parameter)"},
     {"VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-samples-parameter", "samples must be a valid VkSampleCountFlagBits value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetPhysicalDeviceMultisamplePropertiesEXT-samples-parameter)"},
@@ -4603,11 +4889,13 @@
     {"VUID-vkGetRandROutputDisplayEXT-dpy-parameter", "dpy must be a valid pointer to a Display value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRandROutputDisplayEXT-dpy-parameter)"},
     {"VUID-vkGetRandROutputDisplayEXT-pDisplay-parameter", "pDisplay must be a valid pointer to a VkDisplayKHR handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRandROutputDisplayEXT-pDisplay-parameter)"},
     {"VUID-vkGetRandROutputDisplayEXT-physicalDevice-parameter", "physicalDevice must be a valid VkPhysicalDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRandROutputDisplayEXT-physicalDevice-parameter)"},
-    {"VUID-vkGetRaytracingShaderHandlesNVX-dataSize-arraylength", "dataSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRaytracingShaderHandlesNVX-dataSize-arraylength)"},
-    {"VUID-vkGetRaytracingShaderHandlesNVX-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRaytracingShaderHandlesNVX-device-parameter)"},
-    {"VUID-vkGetRaytracingShaderHandlesNVX-pData-parameter", "pData must be a valid pointer to an array of dataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRaytracingShaderHandlesNVX-pData-parameter)"},
-    {"VUID-vkGetRaytracingShaderHandlesNVX-pipeline-parameter", "pipeline must be a valid VkPipeline handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRaytracingShaderHandlesNVX-pipeline-parameter)"},
-    {"VUID-vkGetRaytracingShaderHandlesNVX-pipeline-parent", "pipeline must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRaytracingShaderHandlesNVX-pipeline-parent)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-dataSize-02420", "dataSize must be at least VkPhysicalDeviceRayTracingPropertiesNV::shaderGroupHandleSize {times} groupCount (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-dataSize-02420)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-dataSize-arraylength", "dataSize must be greater than 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-dataSize-arraylength)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-device-parameter)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-firstGroup-02419", "The sum of firstGroup and groupCount must be less than the number of shader groups in pipeline. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-firstGroup-02419)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-pData-parameter", "pData must be a valid pointer to an array of dataSize bytes (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-pData-parameter)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-pipeline-parameter", "pipeline must be a valid VkPipeline handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-pipeline-parameter)"},
+    {"VUID-vkGetRayTracingShaderGroupHandlesNV-pipeline-parent", "pipeline must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRayTracingShaderGroupHandlesNV-pipeline-parent)"},
     {"VUID-vkGetRefreshCycleDurationGOOGLE-commonparent", "Both of device, and swapchain must have been created, allocated, or retrieved from the same VkInstance (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRefreshCycleDurationGOOGLE-commonparent)"},
     {"VUID-vkGetRefreshCycleDurationGOOGLE-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRefreshCycleDurationGOOGLE-device-parameter)"},
     {"VUID-vkGetRefreshCycleDurationGOOGLE-pDisplayTimingProperties-parameter", "pDisplayTimingProperties must be a valid pointer to a VkRefreshCycleDurationGOOGLE structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkGetRefreshCycleDurationGOOGLE-pDisplayTimingProperties-parameter)"},
@@ -4770,6 +5058,8 @@
     {"VUID-vkResetFences-pFences-parameter", "pFences must be a valid pointer to an array of fenceCount valid VkFence handles (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkResetFences-pFences-parameter)"},
     {"VUID-vkResetFences-pFences-parent", "Each element of pFences must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkResetFences-pFences-parent)"},
     {"VUID-vkSetDebugUtilsObjectNameEXT-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectNameEXT-device-parameter)"},
+    {"VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02587", "pNameInfo->objectType must not be VK_OBJECT_TYPE_UNKNOWN (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02587)"},
+    {"VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02588", "pNameInfo->objectHandle must not be VK_NULL_HANDLE (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02588)"},
     {"VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-parameter", "pNameInfo must be a valid pointer to a valid VkDebugUtilsObjectNameInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-parameter)"},
     {"VUID-vkSetDebugUtilsObjectTagEXT-device-parameter", "device must be a valid VkDevice handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectTagEXT-device-parameter)"},
     {"VUID-vkSetDebugUtilsObjectTagEXT-pTagInfo-parameter", "pTagInfo must be a valid pointer to a valid VkDebugUtilsObjectTagInfoEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSetDebugUtilsObjectTagEXT-pTagInfo-parameter)"},
@@ -4785,6 +5075,7 @@
     {"VUID-vkSubmitDebugUtilsMessageEXT-messageSeverity-parameter", "messageSeverity must be a valid VkDebugUtilsMessageSeverityFlagBitsEXT value (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSubmitDebugUtilsMessageEXT-messageSeverity-parameter)"},
     {"VUID-vkSubmitDebugUtilsMessageEXT-messageTypes-parameter", "messageTypes must be a valid combination of VkDebugUtilsMessageTypeFlagBitsEXT values (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSubmitDebugUtilsMessageEXT-messageTypes-parameter)"},
     {"VUID-vkSubmitDebugUtilsMessageEXT-messageTypes-requiredbitmask", "messageTypes must not be 0 (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSubmitDebugUtilsMessageEXT-messageTypes-requiredbitmask)"},
+    {"VUID-vkSubmitDebugUtilsMessageEXT-objectType-02591", "objectType member of each element of pCallbackData->pObjects must not be VK_OBJECT_TYPE_UNKNOWN (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSubmitDebugUtilsMessageEXT-objectType-02591)"},
     {"VUID-vkSubmitDebugUtilsMessageEXT-pCallbackData-parameter", "pCallbackData must be a valid pointer to a valid VkDebugUtilsMessengerCallbackDataEXT structure (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkSubmitDebugUtilsMessageEXT-pCallbackData-parameter)"},
     {"VUID-vkTrimCommandPool-commandPool-parameter", "commandPool must be a valid VkCommandPool handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkTrimCommandPool-commandPool-parameter)"},
     {"VUID-vkTrimCommandPool-commandPool-parent", "commandPool must have been created, allocated, or retrieved from device (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkTrimCommandPool-commandPool-parent)"},
diff --git a/scripts/check_code_format.sh b/scripts/check_code_format.sh
index dde4379..0b5b01c 100755
--- a/scripts/check_code_format.sh
+++ b/scripts/check_code_format.sh
@@ -1,5 +1,6 @@
 #!/bin/bash
-# Copyright (c) 2017 Google Inc.
+# Copyright (c) 2017-2019 Google Inc.
+# Copyright (c) 2019 LunarG, Inc.
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -21,21 +22,45 @@
 RED='\033[0;31m'
 GREEN='\033[0;32m'
 NC='\033[0m' # No Color
+FOUND_ERROR=0
 
 FILES_TO_CHECK=$(git diff --name-only master | grep -v -E "^include/vulkan" | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$")
+COPYRIGHTED_FILES_TO_CHECK=$(git diff --name-only master | grep -v -E "^include/vulkan")
 
 if [ -z "${FILES_TO_CHECK}" ]; then
   echo -e "${GREEN}No source code to check for formatting.${NC}"
-  exit 0
+else
+  # Check source files in PR for clang-format errors
+  FORMAT_DIFF=$(git diff -U0 master -- ${FILES_TO_CHECK} | python ./scripts/clang-format-diff.py -p1 -style=file)
+
+  if [ ! -z "${FORMAT_DIFF}" ]; then
+    echo -e "${RED}Found formatting errors!${NC}"
+    echo "${FORMAT_DIFF}"
+    FOUND_ERROR=1
+  fi
+
+  # Check files in PR out-of-date copyright notices
+  if [ -z "${COPYRIGHTED_FILES_TO_CHECK}" ]; then
+    echo -e "${GREEN}No source code to check for copyright dates.${NC}"
+  else
+    THISYEAR=$(date +"%Y")
+    # Look for current year in copyright lines
+    for AFILE in ${COPYRIGHTED_FILES_TO_CHECK}
+    do
+      COPYRIGHT_INFO=$(cat ${AFILE} | grep -E "Copyright (.)*LunarG")
+      if [ ! -z "${COPYRIGHT_INFO}" ]; then
+        if ! echo "$COPYRIGHT_INFO" | grep -q "$THISYEAR" ; then
+          echo -e "${RED} "$AFILE" has an out-of-date copyright notice.${NC}"
+          FOUND_ERROR=1
+        fi
+      fi
+    done
+  fi
 fi
 
-FORMAT_DIFF=$(git diff -U0 master -- ${FILES_TO_CHECK} | python ./scripts/clang-format-diff.py -p1 -style=file)
-
-if [ -z "${FORMAT_DIFF}" ]; then
+if [ $FOUND_ERROR  -gt 0 ]; then
+  exit 1
+else
   echo -e "${GREEN}All source code in PR properly formatted.${NC}"
   exit 0
-else
-  echo -e "${RED}Found formatting errors!${NC}"
-  echo "${FORMAT_DIFF}"
-  exit 1
 fi
diff --git a/scripts/common_codegen.py b/scripts/common_codegen.py
index 37e0b29..47bb632 100644
--- a/scripts/common_codegen.py
+++ b/scripts/common_codegen.py
@@ -1,8 +1,8 @@
 #!/usr/bin/python3 -i
 #
-# Copyright (c) 2015-2017 The Khronos Group Inc.
-# Copyright (c) 2015-2017 Valve Corporation
-# Copyright (c) 2015-2017 LunarG, Inc.
+# Copyright (c) 2015-2017, 2019 The Khronos Group Inc.
+# Copyright (c) 2015-2017, 2019 Valve Corporation
+# Copyright (c) 2015-2017, 2019 LunarG, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@
 # Copyright text prefixing all headers (list of strings).
 prefixStrings = [
     '/*',
-    '** Copyright (c) 2015-2017 The Khronos Group Inc.',
-    '** Copyright (c) 2015-2017 Valve Corporation',
-    '** Copyright (c) 2015-2017 LunarG, Inc.',
-    '** Copyright (c) 2015-2017 Google Inc.',
+    '** Copyright (c) 2015-2017, 2019 The Khronos Group Inc.',
+    '** Copyright (c) 2015-2017, 2019 Valve Corporation',
+    '** Copyright (c) 2015-2017, 2019 LunarG, Inc.',
+    '** Copyright (c) 2015-2017, 2019 Google Inc.',
     '**',
     '** Licensed under the Apache License, Version 2.0 (the "License");',
     '** you may not use this file except in compliance with the License.',
@@ -52,7 +52,7 @@
     'fuchsia' : 'VK_USE_PLATFORM_FUCHSIA',
     'ios' : 'VK_USE_PLATFORM_IOS_MVK',
     'macos' : 'VK_USE_PLATFORM_MACOS_MVK',
-    'mir' : 'VK_USE_PLATFORM_MIR_KHR',
+    'metal' : 'VK_USE_PLATFORM_METAL_EXT',
     'vi' : 'VK_USE_PLATFORM_VI_NN',
     'wayland' : 'VK_USE_PLATFORM_WAYLAND_KHR',
     'win32' : 'VK_USE_PLATFORM_WIN32_KHR',
diff --git a/scripts/dispatch_table_helper_generator.py b/scripts/dispatch_table_helper_generator.py
index efcfb09..488d8f5 100644
--- a/scripts/dispatch_table_helper_generator.py
+++ b/scripts/dispatch_table_helper_generator.py
@@ -168,27 +168,30 @@
     # Determine if this API should be ignored or added to the instance or device dispatch table
     def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo):
         handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
-        if handle == None:
+        if handle is None:
             return
         if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
             self.device_dispatch_list.append((name, self.featureExtraProtect))
             extension = "VK_VERSION" not in self.featureName
             promoted = not extension and "VK_VERSION_1_0" != self.featureName
-            if promoted or (extension and self.extension_type == 'device'):
+            if promoted or extension:
                 self.device_stub_list.append([name, self.featureName])
                 if extension:
                     self.device_extension_list.append([name, self.featureName])
                 # Build up stub function
                 return_type = ''
                 decl = self.makeCDecls(cmdinfo.elem)[1]
-                if 'typedef VkResult' in decl:
+                if decl.startswith('typedef VkResult'):
                     return_type = 'return VK_SUCCESS;'
-                decl = decl.split('*PFN_vk')[1]
+                elif decl.startswith('typedef VkDeviceAddress'):
+                    return_type = 'return 0;'
+                elif decl.startswith('typedef uint32_t'):
+                    return_type = 'return 0;'
+                pre_decl, decl = decl.split('*PFN_vk')
+                pre_decl = pre_decl.replace('typedef ', '')
+                pre_decl = pre_decl.split(' (')[0]
                 decl = decl.replace(')(', '(')
-                if return_type == '':
-                    decl = 'static VKAPI_ATTR void VKAPI_CALL Stub' + decl
-                else:
-                    decl = 'static VKAPI_ATTR VkResult VKAPI_CALL Stub' + decl
+                decl = 'static VKAPI_ATTR ' + pre_decl + ' VKAPI_CALL Stub' + decl
                 func_body = ' { ' + return_type + ' };'
                 decl = decl.replace (';', func_body)
                 if self.featureExtraProtect is not None:
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index 9e095fb..12084e9 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -192,9 +192,10 @@
         if self.helper_file_type == 'enum_string_header':
             value_set = set()
             for elem in groupElem.findall('enum'):
-                if elem.get('supported') != 'disabled' and elem.get('alias') == None:
+                if elem.get('supported') != 'disabled' and elem.get('alias') is None:
                     value_set.add(elem.get('name'))
-            self.enum_output += self.GenerateEnumStringConversion(groupName, value_set)
+            if value_set != set():
+                self.enum_output += self.GenerateEnumStringConversion(groupName, value_set)
         elif self.helper_file_type == 'object_types_header':
             if groupName == 'VkDebugReportObjectTypeEXT':
                 for elem in groupElem.findall('enum'):
@@ -428,7 +429,7 @@
         for item in self.structMembers:
             if self.NeedSafeStruct(item) == True:
                 safe_struct_header += '\n'
-                if item.ifdef_protect != None:
+                if item.ifdef_protect is not None:
                     safe_struct_header += '#ifdef %s\n' % item.ifdef_protect
                 safe_struct_header += 'struct safe_%s {\n' % (item.name)
                 for member in item.members:
@@ -454,7 +455,7 @@
                 safe_struct_header += '    %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name)
                 safe_struct_header += '    %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name)
                 safe_struct_header += '};\n'
-                if item.ifdef_protect != None:
+                if item.ifdef_protect is not None:
                     safe_struct_header += '#endif // %s\n' % item.ifdef_protect
         return safe_struct_header
     #
@@ -537,10 +538,11 @@
             struct  = [struct_decl]
             struct.extend([ '    bool %s{false};' % field_name[ext_name] for ext_name, info in extension_items])
 
-            # Create struct entries for saving extension count and extension list from DeviceCreateInfo
-            struct.extend([
-                '',
-                '    std::unordered_set<std::string> device_extension_set;'])
+            # Create struct entries for saving extension count and extension list from Instance, DeviceCreateInfo
+            if type == 'Instance':
+                struct.extend([
+                    '',
+                    '    std::unordered_set<std::string> device_extension_set;'])
 
             # Construct the extension information map -- mapping name to data member (field), and required extensions
             # The map is contained within a static function member for portability reasons.
@@ -605,13 +607,13 @@
                     '        // Initialize: this to defaults,  base class fields to input.',
                     '        assert(instance_extensions);',
                     '        *this = %s(*instance_extensions);' % struct_type,
+                    '']),
+            struct.extend([
                     '',
                     '        // Save pCreateInfo device extension list',
                     '        for (uint32_t extn = 0; extn < pCreateInfo->enabledExtensionCount; extn++) {',
                     '           device_extension_set.insert(pCreateInfo->ppEnabledExtensionNames[extn]);',
-                    '        }']),
-
-            struct.extend([
+                    '        }',
                 '',
                 '        static const std::vector<const char *> V_1_0_promoted_%s_extensions = {' % type.lower() ])
             struct.extend(['            %s_EXTENSION_NAME,' % ext_name.upper() for ext_name in promoted_ext_list])
@@ -805,7 +807,7 @@
                 continue
             if item.name in wsi_structs:
                 continue
-            if item.ifdef_protect != None:
+            if item.ifdef_protect is not None:
                 safe_struct_body.append("#ifdef %s\n" % item.ifdef_protect)
             ss_name = "safe_%s" % item.name
             init_list = ''          # list of members in struct constructor initializer
@@ -1116,7 +1118,7 @@
             init_copy = copy_construct_init.replace('src.', 'src->')
             init_construct = copy_construct_txt.replace('src.', 'src->')
             safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct))
-            if item.ifdef_protect != None:
+            if item.ifdef_protect is not None:
                 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect)
         return "\n".join(safe_struct_body)
     #
@@ -1208,7 +1210,7 @@
             if not info:
                 continue
 
-            if item.ifdef_protect != None:
+            if item.ifdef_protect is not None:
                 code.append('#ifdef %s' % item.ifdef_protect)
 
             code.append('// Map type {} to id {}'.format(typename, info.value))
@@ -1216,7 +1218,7 @@
                 id_decl=id_decl, id_member=id_member))
             code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, typedef=type_member))
 
-            if item.ifdef_protect != None:
+            if item.ifdef_protect is not None:
                 code.append('#endif // %s' % item.ifdef_protect)
 
         # Generate utilities for all types
diff --git a/scripts/known_good.json b/scripts/known_good.json
index dfedc6b..8fc3268 100644
--- a/scripts/known_good.json
+++ b/scripts/known_good.json
@@ -6,7 +6,7 @@
       "sub_dir" : "glslang",
       "build_dir" : "glslang/build",
       "install_dir" : "glslang/build/install",
-      "commit" : "91ac4290bcf2cb930b4fb0981f09c00c0b6797e1",
+      "commit" : "5432f0dd8f331f15182681664d7486681e8514e6",
       "prebuild" : [
         "python update_glslang_sources.py"
       ],
@@ -20,7 +20,7 @@
       "sub_dir" : "Vulkan-Headers",
       "build_dir" : "Vulkan-Headers/build",
       "install_dir" : "Vulkan-Headers/build/install",
-      "commit" : "aaca7baef0132f5f8c8f89ee07e3a27aca52b59c"
+      "commit" : "v1.1.102"
     },
     {
       "name" : "Vulkan-Loader",
@@ -28,7 +28,7 @@
       "sub_dir" : "Vulkan-Loader",
       "build_dir" : "Vulkan-Loader/build",
       "install_dir" : "Vulkan-Loader/build/install",
-      "commit" : "953b0807fd4d9487b9c888539ab3adefa4329820",
+      "commit" : "v1.1.102",
       "deps" : [
         {
           "var_name" : "VULKAN_HEADERS_INSTALL_DIR",
@@ -45,7 +45,7 @@
       "sub_dir" : "VulkanTools",
       "build_dir" : "VulkanTools/build",
       "install_dir" : "VulkanTools/build/install",
-      "commit" : "7a298894d73feaf4248afcc33cc5b903c0cf27c7",
+      "commit" : "748a291e0e8b0368d3c7b654b35ebbe226ed622d",
       "deps" : [
         {
           "var_name" : "VULKAN_HEADERS_INSTALL_DIR",
@@ -83,7 +83,7 @@
       "sub_dir" : "Vulkan-Tools",
       "build_dir" : "Vulkan-Tools/build",
       "install_dir" : "Vulkan-Tools/build/install",
-      "commit" : "2e8d601de618eddf2bab8597fd140b2824a060b2",
+      "commit" : "v1.1.102",
       "deps" : [
         {
           "var_name" : "VULKAN_HEADERS_INSTALL_DIR",
diff --git a/scripts/layer_chassis_dispatch_generator.py b/scripts/layer_chassis_dispatch_generator.py
new file mode 100644
index 0000000..f21cb54
--- /dev/null
+++ b/scripts/layer_chassis_dispatch_generator.py
@@ -0,0 +1,1830 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2015-2019 The Khronos Group Inc.
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Tobin Ehlis <tobine@google.com>
+# Author: Mark Lobodzinski <mark@lunarg.com>
+
+import os,re,sys
+import xml.etree.ElementTree as etree
+from generator import *
+from collections import namedtuple
+from common_codegen import *
+
+# LayerChassisDispatchGeneratorOptions - subclass of GeneratorOptions.
+#
+# Adds options used by LayerChassisDispatchOutputGenerator objects during
+# layer chassis dispatch file generation.
+#
+# Additional members
+#   prefixText - list of strings to prefix generated header with
+#     (usually a copyright statement + calling convention macros).
+#   protectFile - True if multiple inclusion protection should be
+#     generated (based on the filename) around the entire header.
+#   protectFeature - True if #ifndef..#endif protection should be
+#     generated around a feature interface in the header file.
+#   genFuncPointers - True if function pointer typedefs should be
+#     generated
+#   protectProto - If conditional protection should be generated
+#     around prototype declarations, set to either '#ifdef'
+#     to require opt-in (#ifdef protectProtoStr) or '#ifndef'
+#     to require opt-out (#ifndef protectProtoStr). Otherwise
+#     set to None.
+#   protectProtoStr - #ifdef/#ifndef symbol to use around prototype
+#     declarations, if protectProto is set
+#   apicall - string to use for the function declaration prefix,
+#     such as APICALL on Windows.
+#   apientry - string to use for the calling convention macro,
+#     in typedefs, such as APIENTRY.
+#   apientryp - string to use for the calling convention macro
+#     in function pointer typedefs, such as APIENTRYP.
+#   indentFuncProto - True if prototype declarations should put each
+#     parameter on a separate line
+#   indentFuncPointer - True if typedefed function pointers should put each
+#     parameter on a separate line
+#   alignFuncParam - if nonzero and parameters are being put on a
+#     separate line, align parameter names at the specified column
+class LayerChassisDispatchGeneratorOptions(GeneratorOptions):
+    def __init__(self,
+                 filename = None,
+                 directory = '.',
+                 apiname = None,
+                 profile = None,
+                 versions = '.*',
+                 emitversions = '.*',
+                 defaultExtensions = None,
+                 addExtensions = None,
+                 removeExtensions = None,
+                 emitExtensions = None,
+                 sortProcedure = regSortFeatures,
+                 prefixText = "",
+                 genFuncPointers = True,
+                 protectFile = True,
+                 protectFeature = True,
+                 apicall = '',
+                 apientry = '',
+                 apientryp = '',
+                 indentFuncProto = True,
+                 indentFuncPointer = False,
+                 alignFuncParam = 0,
+                 expandEnumerants = True):
+        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
+                                  versions, emitversions, defaultExtensions,
+                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        self.prefixText      = prefixText
+        self.genFuncPointers = genFuncPointers
+        self.protectFile     = protectFile
+        self.protectFeature  = protectFeature
+        self.apicall         = apicall
+        self.apientry        = apientry
+        self.apientryp       = apientryp
+        self.indentFuncProto = indentFuncProto
+        self.indentFuncPointer = indentFuncPointer
+        self.alignFuncParam   = alignFuncParam
+        self.expandEnumerants = expandEnumerants
+
+
+# LayerChassisDispatchOutputGenerator - subclass of OutputGenerator.
+# Generates layer chassis non-dispatchable handle-wrapping code.
+#
+# ---- methods ----
+# LayerChassisDispatchOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state.
+# ---- methods overriding base class ----
+# beginFile(genOpts)
+# endFile()
+# beginFeature(interface, emit)
+# endFeature()
+# genCmd(cmdinfo)
+# genStruct()
+# genType()
+class LayerChassisDispatchOutputGenerator(OutputGenerator):
+    """Generate layer chassis handle wrapping code based on XML element attributes"""
+    inline_copyright_message = """
+// This file is ***GENERATED***.  Do Not Edit.
+// See layer_chassis_dispatch_generator.py for modifications.
+
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (c) 2015-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ */"""
+
+    inline_custom_source_preamble = """
+VkResult DispatchCreateComputePipelines(ValidationObject *layer_data,
+                                        VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
+                                        const VkComputePipelineCreateInfo *pCreateInfos,
+                                        const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount,
+                                                                                          pCreateInfos, pAllocator, pPipelines);
+    safe_VkComputePipelineCreateInfo *local_pCreateInfos = NULL;
+    if (pCreateInfos) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        local_pCreateInfos = new safe_VkComputePipelineCreateInfo[createInfoCount];
+        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
+            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]);
+            if (pCreateInfos[idx0].basePipelineHandle) {
+                local_pCreateInfos[idx0].basePipelineHandle = layer_data->Unwrap(pCreateInfos[idx0].basePipelineHandle);
+            }
+            if (pCreateInfos[idx0].layout) {
+                local_pCreateInfos[idx0].layout = layer_data->Unwrap(pCreateInfos[idx0].layout);
+            }
+            if (pCreateInfos[idx0].stage.module) {
+                local_pCreateInfos[idx0].stage.module = layer_data->Unwrap(pCreateInfos[idx0].stage.module);
+            }
+        }
+    }
+    if (pipelineCache) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        pipelineCache = layer_data->Unwrap(pipelineCache);
+    }
+
+    VkResult result = layer_data->device_dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount,
+                                                                               local_pCreateInfos->ptr(), pAllocator, pPipelines);
+    delete[] local_pCreateInfos;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t i = 0; i < createInfoCount; ++i) {
+            if (pPipelines[i] != VK_NULL_HANDLE) {
+                pPipelines[i] = layer_data->WrapNew(pPipelines[i]);
+            }
+        }
+    }
+    return result;
+}
+
+VkResult DispatchCreateGraphicsPipelines(ValidationObject *layer_data,
+                                         VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
+                                         const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                                         const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateGraphicsPipelines(device, pipelineCache, createInfoCount,
+                                                                                           pCreateInfos, pAllocator, pPipelines);
+    safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = nullptr;
+    if (pCreateInfos) {
+        local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount];
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
+            bool uses_color_attachment = false;
+            bool uses_depthstencil_attachment = false;
+            {
+                const auto subpasses_uses_it = layer_data->renderpasses_states.find(layer_data->Unwrap(pCreateInfos[idx0].renderPass));
+                if (subpasses_uses_it != layer_data->renderpasses_states.end()) {
+                    const auto &subpasses_uses = subpasses_uses_it->second;
+                    if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[idx0].subpass))
+                        uses_color_attachment = true;
+                    if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[idx0].subpass))
+                        uses_depthstencil_attachment = true;
+                }
+            }
+
+            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0], uses_color_attachment, uses_depthstencil_attachment);
+
+            if (pCreateInfos[idx0].basePipelineHandle) {
+                local_pCreateInfos[idx0].basePipelineHandle = layer_data->Unwrap(pCreateInfos[idx0].basePipelineHandle);
+            }
+            if (pCreateInfos[idx0].layout) {
+                local_pCreateInfos[idx0].layout = layer_data->Unwrap(pCreateInfos[idx0].layout);
+            }
+            if (pCreateInfos[idx0].pStages) {
+                for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) {
+                    if (pCreateInfos[idx0].pStages[idx1].module) {
+                        local_pCreateInfos[idx0].pStages[idx1].module = layer_data->Unwrap(pCreateInfos[idx0].pStages[idx1].module);
+                    }
+                }
+            }
+            if (pCreateInfos[idx0].renderPass) {
+                local_pCreateInfos[idx0].renderPass = layer_data->Unwrap(pCreateInfos[idx0].renderPass);
+            }
+        }
+    }
+    if (pipelineCache) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        pipelineCache = layer_data->Unwrap(pipelineCache);
+    }
+
+    VkResult result = layer_data->device_dispatch_table.CreateGraphicsPipelines(device, pipelineCache, createInfoCount,
+                                                                                local_pCreateInfos->ptr(), pAllocator, pPipelines);
+    delete[] local_pCreateInfos;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t i = 0; i < createInfoCount; ++i) {
+            if (pPipelines[i] != VK_NULL_HANDLE) {
+                pPipelines[i] = layer_data->WrapNew(pPipelines[i]);
+            }
+        }
+    }
+    return result;
+}
+
+template <typename T>
+static void UpdateCreateRenderPassState(ValidationObject *layer_data, const T *pCreateInfo, VkRenderPass renderPass) {
+    auto &renderpass_state = layer_data->renderpasses_states[renderPass];
+
+    for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
+        bool uses_color = false;
+        for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
+            if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
+
+        bool uses_depthstencil = false;
+        if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
+            if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
+                uses_depthstencil = true;
+
+        if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
+        if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
+    }
+}
+
+VkResult DispatchCreateRenderPass(ValidationObject *layer_data,
+                                  VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                  const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    VkResult result = layer_data->device_dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
+    if (!wrap_handles) return result;
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        UpdateCreateRenderPassState(layer_data, pCreateInfo, *pRenderPass);
+        *pRenderPass = layer_data->WrapNew(*pRenderPass);
+    }
+    return result;
+}
+
+VkResult DispatchCreateRenderPass2KHR(ValidationObject *layer_data,
+                                      VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo,
+                                      const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    VkResult result = layer_data->device_dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass);
+    if (!wrap_handles) return result;
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        UpdateCreateRenderPassState(layer_data, pCreateInfo, *pRenderPass);
+        *pRenderPass = layer_data->WrapNew(*pRenderPass);
+    }
+    return result;
+}
+
+void DispatchDestroyRenderPass(ValidationObject *layer_data,
+                               VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
+    std::unique_lock<std::mutex> lock(dispatch_lock);
+    uint64_t renderPass_id = reinterpret_cast<uint64_t &>(renderPass);
+    renderPass = (VkRenderPass)unique_id_mapping[renderPass_id];
+    unique_id_mapping.erase(renderPass_id);
+    lock.unlock();
+    layer_data->device_dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
+
+    lock.lock();
+    layer_data->renderpasses_states.erase(renderPass);
+}
+
+VkResult DispatchCreateSwapchainKHR(ValidationObject *layer_data,
+                                    VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                    const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
+    safe_VkSwapchainCreateInfoKHR *local_pCreateInfo = NULL;
+    if (pCreateInfo) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        local_pCreateInfo = new safe_VkSwapchainCreateInfoKHR(pCreateInfo);
+        local_pCreateInfo->oldSwapchain = layer_data->Unwrap(pCreateInfo->oldSwapchain);
+        // Surface is instance-level object
+        local_pCreateInfo->surface = layer_data->Unwrap(pCreateInfo->surface);
+    }
+
+    VkResult result = layer_data->device_dispatch_table.CreateSwapchainKHR(device, local_pCreateInfo->ptr(), pAllocator, pSwapchain);
+    delete local_pCreateInfo;
+
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        *pSwapchain = layer_data->WrapNew(*pSwapchain);
+    }
+    return result;
+}
+
+VkResult DispatchCreateSharedSwapchainsKHR(ValidationObject *layer_data,
+                                           VkDevice device, uint32_t swapchainCount,
+                                           const VkSwapchainCreateInfoKHR *pCreateInfos,
+                                           const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos,
+                                                                                          pAllocator, pSwapchains);
+    safe_VkSwapchainCreateInfoKHR *local_pCreateInfos = NULL;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        if (pCreateInfos) {
+            local_pCreateInfos = new safe_VkSwapchainCreateInfoKHR[swapchainCount];
+            for (uint32_t i = 0; i < swapchainCount; ++i) {
+                local_pCreateInfos[i].initialize(&pCreateInfos[i]);
+                if (pCreateInfos[i].surface) {
+                    // Surface is instance-level object
+                    local_pCreateInfos[i].surface = layer_data->Unwrap(pCreateInfos[i].surface);
+                }
+                if (pCreateInfos[i].oldSwapchain) {
+                    local_pCreateInfos[i].oldSwapchain = layer_data->Unwrap(pCreateInfos[i].oldSwapchain);
+                }
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, local_pCreateInfos->ptr(),
+                                                                                  pAllocator, pSwapchains);
+    delete[] local_pCreateInfos;
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t i = 0; i < swapchainCount; i++) {
+            pSwapchains[i] = layer_data->WrapNew(pSwapchains[i]);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetSwapchainImagesKHR(ValidationObject *layer_data,
+                                       VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                       VkImage *pSwapchainImages) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+    VkSwapchainKHR wrapped_swapchain_handle = swapchain;
+    if (VK_NULL_HANDLE != swapchain) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        swapchain = layer_data->Unwrap(swapchain);
+    }
+    VkResult result =
+        layer_data->device_dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+    if ((VK_SUCCESS == result) || (VK_INCOMPLETE == result)) {
+        if ((*pSwapchainImageCount > 0) && pSwapchainImages) {
+            std::lock_guard<std::mutex> lock(dispatch_lock);
+            auto &wrapped_swapchain_image_handles = layer_data->swapchain_wrapped_image_handle_map[wrapped_swapchain_handle];
+            for (uint32_t i = static_cast<uint32_t>(wrapped_swapchain_image_handles.size()); i < *pSwapchainImageCount; i++) {
+                wrapped_swapchain_image_handles.emplace_back(layer_data->WrapNew(pSwapchainImages[i]));
+            }
+            for (uint32_t i = 0; i < *pSwapchainImageCount; i++) {
+                pSwapchainImages[i] = wrapped_swapchain_image_handles[i];
+            }
+        }
+    }
+    return result;
+}
+
+void DispatchDestroySwapchainKHR(ValidationObject *layer_data,
+                                 VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
+    std::unique_lock<std::mutex> lock(dispatch_lock);
+
+    auto &image_array = layer_data->swapchain_wrapped_image_handle_map[swapchain];
+    for (auto &image_handle : image_array) {
+        unique_id_mapping.erase(HandleToUint64(image_handle));
+    }
+    layer_data->swapchain_wrapped_image_handle_map.erase(swapchain);
+
+    uint64_t swapchain_id = HandleToUint64(swapchain);
+    swapchain = (VkSwapchainKHR)unique_id_mapping[swapchain_id];
+    unique_id_mapping.erase(swapchain_id);
+    lock.unlock();
+    layer_data->device_dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
+}
+
+VkResult DispatchQueuePresentKHR(ValidationObject *layer_data,
+                                 VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.QueuePresentKHR(queue, pPresentInfo);
+    safe_VkPresentInfoKHR *local_pPresentInfo = NULL;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        if (pPresentInfo) {
+            local_pPresentInfo = new safe_VkPresentInfoKHR(pPresentInfo);
+            if (local_pPresentInfo->pWaitSemaphores) {
+                for (uint32_t index1 = 0; index1 < local_pPresentInfo->waitSemaphoreCount; ++index1) {
+                    local_pPresentInfo->pWaitSemaphores[index1] = layer_data->Unwrap(pPresentInfo->pWaitSemaphores[index1]);
+                }
+            }
+            if (local_pPresentInfo->pSwapchains) {
+                for (uint32_t index1 = 0; index1 < local_pPresentInfo->swapchainCount; ++index1) {
+                    local_pPresentInfo->pSwapchains[index1] = layer_data->Unwrap(pPresentInfo->pSwapchains[index1]);
+                }
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.QueuePresentKHR(queue, local_pPresentInfo->ptr());
+
+    // pResults is an output array embedded in a structure. The code generator neglects to copy back from the safe_* version,
+    // so handle it as a special case here:
+    if (pPresentInfo && pPresentInfo->pResults) {
+        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
+            pPresentInfo->pResults[i] = local_pPresentInfo->pResults[i];
+        }
+    }
+    delete local_pPresentInfo;
+    return result;
+}
+
+void DispatchDestroyDescriptorPool(ValidationObject *layer_data, VkDevice device, VkDescriptorPool descriptorPool,
+                                   const VkAllocationCallbacks *pAllocator) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
+    std::unique_lock<std::mutex> lock(dispatch_lock);
+
+    // remove references to implicitly freed descriptor sets
+    for(auto descriptor_set : layer_data->pool_descriptor_sets_map[descriptorPool]) {
+        unique_id_mapping.erase(reinterpret_cast<uint64_t &>(descriptor_set));
+    }
+    layer_data->pool_descriptor_sets_map.erase(descriptorPool);
+
+    uint64_t descriptorPool_id = reinterpret_cast<uint64_t &>(descriptorPool);
+    descriptorPool = (VkDescriptorPool)unique_id_mapping[descriptorPool_id];
+    unique_id_mapping.erase(descriptorPool_id);
+    lock.unlock();
+    layer_data->device_dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
+}
+
+VkResult DispatchResetDescriptorPool(ValidationObject *layer_data, VkDevice device, VkDescriptorPool descriptorPool,
+                                     VkDescriptorPoolResetFlags flags) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
+    VkDescriptorPool local_descriptor_pool = VK_NULL_HANDLE;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        local_descriptor_pool = layer_data->Unwrap(descriptorPool);
+    }
+    VkResult result = layer_data->device_dispatch_table.ResetDescriptorPool(device, local_descriptor_pool, flags);
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        // remove references to implicitly freed descriptor sets
+        for(auto descriptor_set : layer_data->pool_descriptor_sets_map[descriptorPool]) {
+            unique_id_mapping.erase(reinterpret_cast<uint64_t &>(descriptor_set));
+        }
+        layer_data->pool_descriptor_sets_map[descriptorPool].clear();
+    }
+
+    return result;
+}
+
+VkResult DispatchAllocateDescriptorSets(ValidationObject *layer_data, VkDevice device,
+                                        const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
+    safe_VkDescriptorSetAllocateInfo *local_pAllocateInfo = NULL;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        if (pAllocateInfo) {
+            local_pAllocateInfo = new safe_VkDescriptorSetAllocateInfo(pAllocateInfo);
+            if (pAllocateInfo->descriptorPool) {
+                local_pAllocateInfo->descriptorPool = layer_data->Unwrap(pAllocateInfo->descriptorPool);
+            }
+            if (local_pAllocateInfo->pSetLayouts) {
+                for (uint32_t index1 = 0; index1 < local_pAllocateInfo->descriptorSetCount; ++index1) {
+                    local_pAllocateInfo->pSetLayouts[index1] = layer_data->Unwrap(local_pAllocateInfo->pSetLayouts[index1]);
+                }
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.AllocateDescriptorSets(
+        device, (const VkDescriptorSetAllocateInfo *)local_pAllocateInfo, pDescriptorSets);
+    if (local_pAllocateInfo) {
+        delete local_pAllocateInfo;
+    }
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        auto &pool_descriptor_sets = layer_data->pool_descriptor_sets_map[pAllocateInfo->descriptorPool];
+        for (uint32_t index0 = 0; index0 < pAllocateInfo->descriptorSetCount; index0++) {
+            pDescriptorSets[index0] = layer_data->WrapNew(pDescriptorSets[index0]);
+            pool_descriptor_sets.insert(pDescriptorSets[index0]);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchFreeDescriptorSets(ValidationObject *layer_data, VkDevice device, VkDescriptorPool descriptorPool,
+                                    uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) {
+    if (!wrap_handles)
+        return layer_data->device_dispatch_table.FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets);
+    VkDescriptorSet *local_pDescriptorSets = NULL;
+    VkDescriptorPool local_descriptor_pool = VK_NULL_HANDLE;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        local_descriptor_pool = layer_data->Unwrap(descriptorPool);
+        if (pDescriptorSets) {
+            local_pDescriptorSets = new VkDescriptorSet[descriptorSetCount];
+            for (uint32_t index0 = 0; index0 < descriptorSetCount; ++index0) {
+                local_pDescriptorSets[index0] = layer_data->Unwrap(pDescriptorSets[index0]);
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.FreeDescriptorSets(device, local_descriptor_pool, descriptorSetCount,
+                                                                           (const VkDescriptorSet *)local_pDescriptorSets);
+    if (local_pDescriptorSets) delete[] local_pDescriptorSets;
+    if ((VK_SUCCESS == result) && (pDescriptorSets)) {
+        std::unique_lock<std::mutex> lock(dispatch_lock);
+        auto &pool_descriptor_sets = layer_data->pool_descriptor_sets_map[descriptorPool];
+        for (uint32_t index0 = 0; index0 < descriptorSetCount; index0++) {
+            VkDescriptorSet handle = pDescriptorSets[index0];
+            pool_descriptor_sets.erase(handle);
+            uint64_t unique_id = reinterpret_cast<uint64_t &>(handle);
+            unique_id_mapping.erase(unique_id);
+        }
+    }
+    return result;
+}
+
+
+// This is the core version of this routine.  The extension version is below.
+VkResult DispatchCreateDescriptorUpdateTemplate(ValidationObject *layer_data,
+                                                VkDevice device,
+                                                const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator,
+                                                VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator,
+                                                                                               pDescriptorUpdateTemplate);
+    safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        if (pCreateInfo) {
+            local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo);
+            if (pCreateInfo->descriptorSetLayout) {
+                local_create_info->descriptorSetLayout = layer_data->Unwrap(pCreateInfo->descriptorSetLayout);
+            }
+            if (pCreateInfo->pipelineLayout) {
+                local_create_info->pipelineLayout = layer_data->Unwrap(pCreateInfo->pipelineLayout);
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.CreateDescriptorUpdateTemplate(device, local_create_info->ptr(), pAllocator,
+                                                                                       pDescriptorUpdateTemplate);
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        *pDescriptorUpdateTemplate = layer_data->WrapNew(*pDescriptorUpdateTemplate);
+
+        // Shadow template createInfo for later updates
+        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
+        layer_data->desc_template_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state);
+    }
+    return result;
+}
+
+// This is the extension version of this routine.  The core version is above.
+VkResult DispatchCreateDescriptorUpdateTemplateKHR(ValidationObject *layer_data,
+                                                   VkDevice device,
+                                                   const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
+                                                   const VkAllocationCallbacks *pAllocator,
+                                                   VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator,
+                                                                                                  pDescriptorUpdateTemplate);
+    safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        if (pCreateInfo) {
+            local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo);
+            if (pCreateInfo->descriptorSetLayout) {
+                local_create_info->descriptorSetLayout = layer_data->Unwrap(pCreateInfo->descriptorSetLayout);
+            }
+            if (pCreateInfo->pipelineLayout) {
+                local_create_info->pipelineLayout = layer_data->Unwrap(pCreateInfo->pipelineLayout);
+            }
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.CreateDescriptorUpdateTemplateKHR(device, local_create_info->ptr(), pAllocator,
+                                                                                          pDescriptorUpdateTemplate);
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        *pDescriptorUpdateTemplate = layer_data->WrapNew(*pDescriptorUpdateTemplate);
+
+        // Shadow template createInfo for later updates
+        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
+        layer_data->desc_template_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state);
+    }
+    return result;
+}
+
+// This is the core version of this routine.  The extension version is below.
+void DispatchDestroyDescriptorUpdateTemplate(ValidationObject *layer_data,
+                                             VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                             const VkAllocationCallbacks *pAllocator) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+    std::unique_lock<std::mutex> lock(dispatch_lock);
+    uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
+    layer_data->desc_template_map.erase(descriptor_update_template_id);
+    descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[descriptor_update_template_id];
+    unique_id_mapping.erase(descriptor_update_template_id);
+    lock.unlock();
+    layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+// This is the extension version of this routine.  The core version is above.
+void DispatchDestroyDescriptorUpdateTemplateKHR(ValidationObject *layer_data,
+                                                VkDevice device,
+                                                VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                const VkAllocationCallbacks *pAllocator) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
+    std::unique_lock<std::mutex> lock(dispatch_lock);
+    uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
+    layer_data->desc_template_map.erase(descriptor_update_template_id);
+    descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[descriptor_update_template_id];
+    unique_id_mapping.erase(descriptor_update_template_id);
+    lock.unlock();
+    layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
+}
+
+void *BuildUnwrappedUpdateTemplateBuffer(ValidationObject *layer_data, uint64_t descriptorUpdateTemplate, const void *pData) {
+    auto const template_map_entry = layer_data->desc_template_map.find(descriptorUpdateTemplate);
+    if (template_map_entry == layer_data->desc_template_map.end()) {
+        assert(0);
+    }
+    auto const &create_info = template_map_entry->second->create_info;
+    size_t allocation_size = 0;
+    std::vector<std::tuple<size_t, VulkanObjectType, void *, size_t>> template_entries;
+
+    for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) {
+        for (uint32_t j = 0; j < create_info.pDescriptorUpdateEntries[i].descriptorCount; j++) {
+            size_t offset = create_info.pDescriptorUpdateEntries[i].offset + j * create_info.pDescriptorUpdateEntries[i].stride;
+            char *update_entry = (char *)(pData) + offset;
+
+            switch (create_info.pDescriptorUpdateEntries[i].descriptorType) {
+                case VK_DESCRIPTOR_TYPE_SAMPLER:
+                case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+                case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+                case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+                case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
+                    auto image_entry = reinterpret_cast<VkDescriptorImageInfo *>(update_entry);
+                    allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorImageInfo));
+
+                    VkDescriptorImageInfo *wrapped_entry = new VkDescriptorImageInfo(*image_entry);
+                    wrapped_entry->sampler = layer_data->Unwrap(image_entry->sampler);
+                    wrapped_entry->imageView = layer_data->Unwrap(image_entry->imageView);
+                    template_entries.emplace_back(offset, kVulkanObjectTypeImage, reinterpret_cast<void *>(wrapped_entry), 0);
+                } break;
+
+                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
+                    auto buffer_entry = reinterpret_cast<VkDescriptorBufferInfo *>(update_entry);
+                    allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorBufferInfo));
+
+                    VkDescriptorBufferInfo *wrapped_entry = new VkDescriptorBufferInfo(*buffer_entry);
+                    wrapped_entry->buffer = layer_data->Unwrap(buffer_entry->buffer);
+                    template_entries.emplace_back(offset, kVulkanObjectTypeBuffer, reinterpret_cast<void *>(wrapped_entry), 0);
+                } break;
+
+                case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+                case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
+                    auto buffer_view_handle = reinterpret_cast<VkBufferView *>(update_entry);
+                    allocation_size = std::max(allocation_size, offset + sizeof(VkBufferView));
+
+                    VkBufferView wrapped_entry = layer_data->Unwrap(*buffer_view_handle);
+                    template_entries.emplace_back(offset, kVulkanObjectTypeBufferView, reinterpret_cast<void *>(wrapped_entry), 0);
+                } break;
+                case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
+                    size_t numBytes = create_info.pDescriptorUpdateEntries[i].descriptorCount;
+                    allocation_size = std::max(allocation_size, offset + numBytes);
+                    // nothing to unwrap, just plain data
+                    template_entries.emplace_back(offset, kVulkanObjectTypeUnknown, reinterpret_cast<void *>(update_entry),
+                                                  numBytes);
+                    // to break out of the loop
+                    j = create_info.pDescriptorUpdateEntries[i].descriptorCount;
+                } break;
+                default:
+                    assert(0);
+                    break;
+            }
+        }
+    }
+    // Allocate required buffer size and populate with source/unwrapped data
+    void *unwrapped_data = malloc(allocation_size);
+    for (auto &this_entry : template_entries) {
+        VulkanObjectType type = std::get<1>(this_entry);
+        void *destination = (char *)unwrapped_data + std::get<0>(this_entry);
+        void *source = (char *)std::get<2>(this_entry);
+        size_t size = std::get<3>(this_entry);
+
+        if (size != 0) {
+            assert(type == kVulkanObjectTypeUnknown);
+            memcpy(destination, source, size);
+        } else {
+            switch (type) {
+                case kVulkanObjectTypeImage:
+                    *(reinterpret_cast<VkDescriptorImageInfo *>(destination)) =
+                        *(reinterpret_cast<VkDescriptorImageInfo *>(source));
+                    delete reinterpret_cast<VkDescriptorImageInfo *>(source);
+                    break;
+                case kVulkanObjectTypeBuffer:
+                    *(reinterpret_cast<VkDescriptorBufferInfo *>(destination)) =
+                        *(reinterpret_cast<VkDescriptorBufferInfo *>(source));
+                    delete reinterpret_cast<VkDescriptorBufferInfo *>(source);
+                    break;
+                case kVulkanObjectTypeBufferView:
+                    *(reinterpret_cast<VkBufferView *>(destination)) = reinterpret_cast<VkBufferView>(source);
+                    break;
+                default:
+                    assert(0);
+                    break;
+            }
+        }
+    }
+    return (void *)unwrapped_data;
+}
+
+void DispatchUpdateDescriptorSetWithTemplate(ValidationObject *layer_data,
+                                             VkDevice device, VkDescriptorSet descriptorSet,
+                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                             const void *pData) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        descriptorSet = layer_data->Unwrap(descriptorSet);
+        descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[template_handle];
+    }
+    void *unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData);
+    layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer);
+    free(unwrapped_buffer);
+}
+
+void DispatchUpdateDescriptorSetWithTemplateKHR(ValidationObject *layer_data,
+                                                VkDevice device, VkDescriptorSet descriptorSet,
+                                                VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                const void *pData) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
+    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
+    void *unwrapped_buffer = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        descriptorSet = layer_data->Unwrap(descriptorSet);
+        descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)unique_id_mapping[template_handle];
+        unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData);
+    }
+    layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer);
+    free(unwrapped_buffer);
+}
+
+void DispatchCmdPushDescriptorSetWithTemplateKHR(ValidationObject *layer_data,
+                                                 VkCommandBuffer commandBuffer,
+                                                 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+                                                 VkPipelineLayout layout, uint32_t set, const void *pData) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
+    uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate);
+    void *unwrapped_buffer = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        descriptorUpdateTemplate = layer_data->Unwrap(descriptorUpdateTemplate);
+        layout = layer_data->Unwrap(layout);
+        unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData);
+    }
+    layer_data->device_dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set,
+                                                                 unwrapped_buffer);
+    free(unwrapped_buffer);
+}
+
+VkResult DispatchGetPhysicalDeviceDisplayPropertiesKHR(ValidationObject *layer_data,
+                                                       VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                       VkDisplayPropertiesKHR *pProperties) {
+    VkResult result =
+        layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, pProperties);
+    if (!wrap_handles) return result;
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            pProperties[idx0].display = layer_data->MaybeWrapDisplay(pProperties[idx0].display, layer_data);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetPhysicalDeviceDisplayProperties2KHR(ValidationObject *layer_data,
+                                                        VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                        VkDisplayProperties2KHR *pProperties) {
+    VkResult result =
+        layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, pPropertyCount, pProperties);
+    if (!wrap_handles) return result;
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            pProperties[idx0].displayProperties.display =
+                layer_data->MaybeWrapDisplay(pProperties[idx0].displayProperties.display, layer_data);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetPhysicalDeviceDisplayPlanePropertiesKHR(ValidationObject *layer_data,
+                                                            VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                            VkDisplayPlanePropertiesKHR *pProperties) {
+
+    VkResult result =
+        layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties);
+    if (!wrap_handles) return result;
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            VkDisplayKHR &opt_display = pProperties[idx0].currentDisplay;
+            if (opt_display) opt_display = layer_data->MaybeWrapDisplay(opt_display, layer_data);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetPhysicalDeviceDisplayPlaneProperties2KHR(ValidationObject *layer_data,VkPhysicalDevice physicalDevice,
+                                                             uint32_t *pPropertyCount,
+                                                             VkDisplayPlaneProperties2KHR *pProperties) {
+
+    VkResult result =
+        layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPlaneProperties2KHR(physicalDevice, pPropertyCount, pProperties);
+    if (!wrap_handles) return result;
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            VkDisplayKHR &opt_display = pProperties[idx0].displayPlaneProperties.currentDisplay;
+            if (opt_display) opt_display = layer_data->MaybeWrapDisplay(opt_display, layer_data);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetDisplayPlaneSupportedDisplaysKHR(ValidationObject *layer_data,
+                                                     VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                     uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
+    VkResult result =
+        layer_data->instance_dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pDisplays) {
+    if (!wrap_handles) return result;
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t i = 0; i < *pDisplayCount; ++i) {
+            if (pDisplays[i]) pDisplays[i] = layer_data->MaybeWrapDisplay(pDisplays[i], layer_data);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetDisplayModePropertiesKHR(ValidationObject *layer_data,
+                                             VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                             uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties) {
+    if (!wrap_handles) return layer_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        display = layer_data->Unwrap(display);
+    }
+
+    VkResult result = layer_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties);
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            pProperties[idx0].displayMode = layer_data->WrapNew(pProperties[idx0].displayMode);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchGetDisplayModeProperties2KHR(ValidationObject *layer_data,
+                                              VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                              uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties) {
+    if (!wrap_handles) return layer_data->instance_dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        display = layer_data->Unwrap(display);
+    }
+
+    VkResult result =
+        layer_data->instance_dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties);
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            pProperties[idx0].displayModeProperties.displayMode = layer_data->WrapNew(pProperties[idx0].displayModeProperties.displayMode);
+        }
+    }
+    return result;
+}
+
+VkResult DispatchDebugMarkerSetObjectTagEXT(ValidationObject *layer_data,
+                                            VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DebugMarkerSetObjectTagEXT(device, pTagInfo);
+    safe_VkDebugMarkerObjectTagInfoEXT local_tag_info(pTagInfo);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.object));
+        if (it != unique_id_mapping.end()) {
+            local_tag_info.object = it->second;
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.DebugMarkerSetObjectTagEXT(device, 
+                                                                                   reinterpret_cast<VkDebugMarkerObjectTagInfoEXT *>(&local_tag_info));
+    return result;
+}
+
+VkResult DispatchDebugMarkerSetObjectNameEXT(ValidationObject *layer_data,
+                                             VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.DebugMarkerSetObjectNameEXT(device, pNameInfo);
+    safe_VkDebugMarkerObjectNameInfoEXT local_name_info(pNameInfo);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.object));
+        if (it != unique_id_mapping.end()) {
+            local_name_info.object = it->second;
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.DebugMarkerSetObjectNameEXT(
+        device, reinterpret_cast<VkDebugMarkerObjectNameInfoEXT *>(&local_name_info));
+    return result;
+}
+
+// VK_EXT_debug_utils
+VkResult DispatchSetDebugUtilsObjectTagEXT(ValidationObject *layer_data,
+                                           VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo);
+    safe_VkDebugUtilsObjectTagInfoEXT local_tag_info(pTagInfo);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.objectHandle));
+        if (it != unique_id_mapping.end()) {
+            local_tag_info.objectHandle = it->second;
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.SetDebugUtilsObjectTagEXT(
+        device, reinterpret_cast<const VkDebugUtilsObjectTagInfoEXT *>(&local_tag_info));
+    return result;
+}
+
+VkResult DispatchSetDebugUtilsObjectNameEXT(ValidationObject *layer_data,
+                                            VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
+    if (!wrap_handles) return layer_data->device_dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo);
+    safe_VkDebugUtilsObjectNameInfoEXT local_name_info(pNameInfo);
+    {
+        std::lock_guard<std::mutex> lock(dispatch_lock);
+        auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.objectHandle));
+        if (it != unique_id_mapping.end()) {
+            local_name_info.objectHandle = it->second;
+        }
+    }
+    VkResult result = layer_data->device_dispatch_table.SetDebugUtilsObjectNameEXT(
+        device, reinterpret_cast<const VkDebugUtilsObjectNameInfoEXT *>(&local_name_info));
+    return result;
+}
+
+"""
+    # Separate generated text for source and headers
+    ALL_SECTIONS = ['source_file', 'header_file']
+    def __init__(self,
+                 errFile = sys.stderr,
+                 warnFile = sys.stderr,
+                 diagFile = sys.stdout):
+        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+        self.INDENT_SPACES = 4
+        self.instance_extensions = []
+        self.device_extensions = []
+        # Commands which are not autogenerated but still intercepted
+        self.no_autogen_list = [
+            'vkCreateInstance',
+            'vkDestroyInstance',
+            'vkCreateDevice',
+            'vkDestroyDevice',
+            'vkCreateComputePipelines',
+            'vkCreateGraphicsPipelines',
+            'vkCreateSwapchainKHR',
+            'vkCreateSharedSwapchainsKHR',
+            'vkGetSwapchainImagesKHR',
+            'vkDestroySwapchainKHR',
+            'vkQueuePresentKHR',
+            'vkResetDescriptorPool',
+            'vkDestroyDescriptorPool',
+            'vkAllocateDescriptorSets',
+            'vkFreeDescriptorSets',
+            'vkCreateDescriptorUpdateTemplate',
+            'vkCreateDescriptorUpdateTemplateKHR',
+            'vkDestroyDescriptorUpdateTemplate',
+            'vkDestroyDescriptorUpdateTemplateKHR',
+            'vkUpdateDescriptorSetWithTemplate',
+            'vkUpdateDescriptorSetWithTemplateKHR',
+            'vkCmdPushDescriptorSetWithTemplateKHR',
+            'vkDebugMarkerSetObjectTagEXT',
+            'vkDebugMarkerSetObjectNameEXT',
+            'vkCreateRenderPass',
+            'vkCreateRenderPass2KHR',
+            'vkDestroyRenderPass',
+            'vkSetDebugUtilsObjectNameEXT',
+            'vkSetDebugUtilsObjectTagEXT',
+            'vkGetPhysicalDeviceDisplayPropertiesKHR',
+            'vkGetPhysicalDeviceDisplayProperties2KHR',
+            'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
+            'vkGetPhysicalDeviceDisplayPlaneProperties2KHR',
+            'vkGetDisplayPlaneSupportedDisplaysKHR',
+            'vkGetDisplayModePropertiesKHR',
+            'vkGetDisplayModeProperties2KHR',
+            'vkEnumerateInstanceExtensionProperties',
+            'vkEnumerateInstanceLayerProperties',
+            'vkEnumerateDeviceExtensionProperties',
+            'vkEnumerateDeviceLayerProperties',
+            'vkEnumerateInstanceVersion',
+            ]
+        self.headerVersion = None
+        # Internal state - accumulators for different inner block text
+        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+
+        self.cmdMembers = []
+        self.cmd_feature_protect = []  # Save ifdef's for each command
+        self.cmd_info_data = []        # Save the cmdinfo data for wrapping the handles when processing is complete
+        self.structMembers = []        # List of StructMemberData records for all Vulkan structs
+        self.extension_structs = []    # List of all structs or sister-structs containing handles
+                                       # A sister-struct may contain no handles but shares a structextends attribute with one that does
+        self.pnext_extension_structs = []    # List of all structs which can be extended by a pnext chain
+        self.structTypes = dict()      # Map of Vulkan struct typename to required VkStructureType
+        self.struct_member_dict = dict()
+        # Named tuples to store struct and command data
+        self.StructType = namedtuple('StructType', ['name', 'value'])
+        self.CmdMemberData = namedtuple('CmdMemberData', ['name', 'members'])
+        self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo'])
+        self.CmdExtraProtect = namedtuple('CmdExtraProtect', ['name', 'extra_protect'])
+
+        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy', 'feature_protect'])
+        self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
+    #
+    def incIndent(self, indent):
+        inc = ' ' * self.INDENT_SPACES
+        if indent:
+            return indent + inc
+        return inc
+    #
+    def decIndent(self, indent):
+        if indent and (len(indent) > self.INDENT_SPACES):
+            return indent[:-self.INDENT_SPACES]
+        return ''
+    #
+    # Override makeProtoName to drop the "vk" prefix
+    def makeProtoName(self, name, tail):
+        return self.genOpts.apientry + name[2:] + tail
+    #
+    # Check if the parameter passed in is a pointer to an array
+    def paramIsArray(self, param):
+        return param.attrib.get('len') is not None
+    #
+    def beginFile(self, genOpts):
+        OutputGenerator.beginFile(self, genOpts)
+        self.appendSection('header_file', self.inline_copyright_message)
+        # Multiple inclusion protection & C++ namespace.
+        self.header = False
+        if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
+            self.header = True
+            self.appendSection('header_file', '#pragma once')
+            self.appendSection('header_file', '')
+            self.appendSection('header_file', '#if defined(LAYER_CHASSIS_CAN_WRAP_HANDLES)')
+            self.appendSection('header_file', 'extern bool wrap_handles;')
+            self.appendSection('header_file', '#else')
+            self.appendSection('header_file', 'extern const bool wrap_handles;')
+            self.appendSection('header_file', '#endif')
+
+    # Now that the data is all collected and complete, generate and output the wrapping/unwrapping routines
+    def endFile(self):
+        self.struct_member_dict = dict(self.structMembers)
+        # Generate the list of APIs that might need to handle wrapped extension structs
+        self.GenerateCommandWrapExtensionList()
+        # Write out wrapping/unwrapping functions
+        self.WrapCommands()
+        # Build and write out pNext processing function
+        extension_proc = self.build_extension_processing_func()
+
+        if not self.header:
+            write(self.inline_copyright_message, file=self.outFile)
+            self.newline()
+            write('#include <mutex>', file=self.outFile)
+            write('#include "chassis.h"', file=self.outFile)
+            write('#include "layer_chassis_dispatch.h"', file=self.outFile)
+            self.newline()
+            write('// This intentionally includes a cpp file', file=self.outFile)
+            write('#include "vk_safe_struct.cpp"', file=self.outFile)
+            self.newline()
+            write('std::mutex dispatch_lock;', file=self.outFile)
+            self.newline()
+            write('// Unique Objects pNext extension handling function', file=self.outFile)
+            write('%s' % extension_proc, file=self.outFile)
+            self.newline()
+            write('// Manually written Dispatch routines', file=self.outFile)
+            write('%s' % self.inline_custom_source_preamble, file=self.outFile)
+            self.newline()
+            if (self.sections['source_file']):
+                write('\n'.join(self.sections['source_file']), end=u'', file=self.outFile)
+        else:
+            self.newline()
+            if (self.sections['header_file']):
+                write('\n'.join(self.sections['header_file']), end=u'', file=self.outFile)
+
+        # Finish processing in superclass
+        OutputGenerator.endFile(self)
+    #
+    def beginFeature(self, interface, emit):
+        # Start processing in superclass
+        OutputGenerator.beginFeature(self, interface, emit)
+        self.headerVersion = None
+        self.featureExtraProtect = GetFeatureProtect(interface)
+        if self.featureName != 'VK_VERSION_1_0' and self.featureName != 'VK_VERSION_1_1':
+            white_list_entry = []
+            if (self.featureExtraProtect is not None):
+                white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ]
+            white_list_entry += [ '"%s"' % self.featureName ]
+            if (self.featureExtraProtect is not None):
+                white_list_entry += [ '#endif' ]
+            featureType = interface.get('type')
+            if featureType == 'instance':
+                self.instance_extensions += white_list_entry
+            elif featureType == 'device':
+                self.device_extensions += white_list_entry
+    #
+    def endFeature(self):
+        # Finish processing in superclass
+        OutputGenerator.endFeature(self)
+    #
+    def genType(self, typeinfo, name, alias):
+        OutputGenerator.genType(self, typeinfo, name, alias)
+        typeElem = typeinfo.elem
+        # If the type is a struct type, traverse the imbedded <member> tags generating a structure.
+        # Otherwise, emit the tag text.
+        category = typeElem.get('category')
+        if (category == 'struct' or category == 'union'):
+            self.genStruct(typeinfo, name, alias)
+    #
+    # Append a definition to the specified section
+    def appendSection(self, section, text):
+        # self.sections[section].append('SECTION: ' + section + '\n')
+        self.sections[section].append(text)
+    #
+    # Check if the parameter passed in is a pointer
+    def paramIsPointer(self, param):
+        ispointer = False
+        for elem in param:
+            if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
+                ispointer = True
+        return ispointer
+    #
+    # Get the category of a type
+    def getTypeCategory(self, typename):
+        types = self.registry.tree.findall("types/type")
+        for elem in types:
+            if (elem.find("name") is not None and elem.find('name').text == typename) or elem.attrib.get('name') == typename:
+                return elem.attrib.get('category')
+    #
+    # Check if a parent object is dispatchable or not
+    def isHandleTypeNonDispatchable(self, handletype):
+        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+        if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
+            return True
+        else:
+            return False
+    #
+    # Retrieve the type and name for a parameter
+    def getTypeNameTuple(self, param):
+        type = ''
+        name = ''
+        for elem in param:
+            if elem.tag == 'type':
+                type = noneStr(elem.text)
+            elif elem.tag == 'name':
+                name = noneStr(elem.text)
+        return (type, name)
+    #
+    # Retrieve the value of the len tag
+    def getLen(self, param):
+        result = None
+        len = param.attrib.get('len')
+        if len and len != 'null-terminated':
+            # For string arrays, 'len' can look like 'count,null-terminated', indicating that we
+            # have a null terminated array of strings.  We strip the null-terminated from the
+            # 'len' field and only return the parameter specifying the string count
+            if 'null-terminated' in len:
+                result = len.split(',')[0]
+            else:
+                result = len
+            # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol
+            result = str(result).replace('::', '->')
+        return result
+    #
+    # Generate a VkStructureType based on a structure typename
+    def genVkStructureType(self, typename):
+        # Add underscore between lowercase then uppercase
+        value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
+        # Change to uppercase
+        value = value.upper()
+        # Add STRUCTURE_TYPE_
+        return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
+    #
+    # Struct parameter check generation.
+    # This is a special case of the <type> tag where the contents are interpreted as a set of
+    # <member> tags instead of freeform C type declarations. The <member> tags are just like
+    # <param> tags - they are a declaration of a struct or union member. Only simple member
+    # declarations are supported (no nested structs etc.)
+    def genStruct(self, typeinfo, typeName, alias):
+        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
+        members = typeinfo.elem.findall('.//member')
+        # Iterate over members once to get length parameters for arrays
+        lens = set()
+        for member in members:
+            len = self.getLen(member)
+            if len:
+                lens.add(len)
+        # Generate member info
+        membersInfo = []
+        for member in members:
+            # Get the member's type and name
+            info = self.getTypeNameTuple(member)
+            type = info[0]
+            name = info[1]
+            cdecl = self.makeCParamDecl(member, 0)
+            # Process VkStructureType
+            if type == 'VkStructureType':
+                # Extract the required struct type value from the comments
+                # embedded in the original text defining the 'typeinfo' element
+                rawXml = etree.tostring(typeinfo.elem).decode('ascii')
+                result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
+                if result:
+                    value = result.group(0)
+                else:
+                    value = self.genVkStructureType(typeName)
+                # Store the required type value
+                self.structTypes[typeName] = self.StructType(name=name, value=value)
+            # Store pointer/array/string info
+            extstructs = self.registry.validextensionstructs[typeName] if name == 'pNext' else None
+            membersInfo.append(self.CommandParam(type=type,
+                                                 name=name,
+                                                 ispointer=self.paramIsPointer(member),
+                                                 isconst=True if 'const' in cdecl else False,
+                                                 iscount=True if name in lens else False,
+                                                 len=self.getLen(member),
+                                                 extstructs=extstructs,
+                                                 cdecl=cdecl,
+                                                 islocal=False,
+                                                 iscreate=False,
+                                                 isdestroy=False,
+                                                 feature_protect=self.featureExtraProtect))
+        self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
+
+    #
+    # Insert a lock_guard line
+    def lock_guard(self, indent):
+        return '%sstd::lock_guard<std::mutex> lock(dispatch_lock);\n' % indent
+    #
+    # Determine if a struct has an NDO as a member or an embedded member
+    def struct_contains_ndo(self, struct_item):
+        struct_member_dict = dict(self.structMembers)
+        struct_members = struct_member_dict[struct_item]
+
+        for member in struct_members:
+            if self.isHandleTypeNonDispatchable(member.type):
+                return True
+            elif member.type in struct_member_dict:
+                if self.struct_contains_ndo(member.type) == True:
+                    return True
+        return False
+    #
+    # Return list of struct members which contain, or which sub-structures contain
+    # an NDO in a given list of parameters or members
+    def getParmeterStructsWithNdos(self, item_list):
+        struct_list = set()
+        for item in item_list:
+            paramtype = item.find('type')
+            typecategory = self.getTypeCategory(paramtype.text)
+            if typecategory == 'struct':
+                if self.struct_contains_ndo(paramtype.text) == True:
+                    struct_list.add(item)
+        return struct_list
+    #
+    # Return list of non-dispatchable objects from a given list of parameters or members
+    def getNdosInParameterList(self, item_list, create_func):
+        ndo_list = set()
+        if create_func == True:
+            member_list = item_list[0:-1]
+        else:
+            member_list = item_list
+        for item in member_list:
+            if self.isHandleTypeNonDispatchable(paramtype.text):
+                ndo_list.add(item)
+        return ndo_list
+    #
+    # Construct list of extension structs containing handles, or extension structs that share a structextends attribute
+    # WITH an extension struct containing handles. All extension structs in any pNext chain will have to be copied.
+    # TODO: make this recursive -- structs buried three or more levels deep are not searched for extensions
+    def GenerateCommandWrapExtensionList(self):
+        for struct in self.structMembers:
+            if (len(struct.members) > 1) and struct.members[1].extstructs is not None:
+                found = False;
+                for item in struct.members[1].extstructs:
+                    if item != '' and item not in self.pnext_extension_structs:
+                        self.pnext_extension_structs.append(item)
+                    if item != '' and self.struct_contains_ndo(item) == True:
+                        found = True
+                if found == True:
+                    for item in struct.members[1].extstructs:
+                        if item != '' and item not in self.extension_structs:
+                            self.extension_structs.append(item)
+    #
+    # Returns True if a struct may have a pNext chain containing an NDO
+    def StructWithExtensions(self, struct_type):
+        if struct_type in self.struct_member_dict:
+            param_info = self.struct_member_dict[struct_type]
+            if (len(param_info) > 1) and param_info[1].extstructs is not None:
+                for item in param_info[1].extstructs:
+                    if item in self.extension_structs:
+                        return True
+        return False
+    #
+    # Generate pNext handling function
+    def build_extension_processing_func(self):
+        # Construct helper functions to build and free pNext extension chains
+        pnext_proc = ''
+        pnext_proc += 'void *CreateUnwrappedExtensionStructs(ValidationObject *layer_data, const void *pNext) {\n'
+        pnext_proc += '    void *cur_pnext = const_cast<void *>(pNext);\n'
+        pnext_proc += '    void *head_pnext = NULL;\n'
+        pnext_proc += '    void *prev_ext_struct = NULL;\n'
+        pnext_proc += '    void *cur_ext_struct = NULL;\n\n'
+        pnext_proc += '    while (cur_pnext != NULL) {\n'
+        pnext_proc += '        VkBaseOutStructure *header = reinterpret_cast<VkBaseOutStructure *>(cur_pnext);\n\n'
+        pnext_proc += '        switch (header->sType) {\n'
+        for item in self.pnext_extension_structs:
+            struct_info = self.struct_member_dict[item]
+            if struct_info[0].feature_protect is not None:
+                pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect
+            pnext_proc += '            case %s: {\n' % self.structTypes[item].value
+            pnext_proc += '                    safe_%s *safe_struct = new safe_%s;\n' % (item, item)
+            pnext_proc += '                    safe_struct->initialize(reinterpret_cast<const %s *>(cur_pnext));\n' % item
+            # Generate code to unwrap the handles
+            indent = '                '
+            (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, 'safe_struct->', 0, False, False, False, False)
+            pnext_proc += tmp_pre
+            pnext_proc += '                    cur_ext_struct = reinterpret_cast<void *>(safe_struct);\n'
+            pnext_proc += '                } break;\n'
+            if struct_info[0].feature_protect is not None:
+                pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect
+            pnext_proc += '\n'
+        pnext_proc += '            default:\n'
+        pnext_proc += '                break;\n'
+        pnext_proc += '        }\n\n'
+        pnext_proc += '        // Save pointer to the first structure in the pNext chain\n'
+        pnext_proc += '        head_pnext = (head_pnext ? head_pnext : cur_ext_struct);\n\n'
+        pnext_proc += '        // For any extension structure but the first, link the last struct\'s pNext to the current ext struct\n'
+        pnext_proc += '        if (prev_ext_struct) {\n'
+        pnext_proc += '                reinterpret_cast<VkBaseOutStructure *>(prev_ext_struct)->pNext = reinterpret_cast<VkBaseOutStructure *>(cur_ext_struct);\n'
+        pnext_proc += '        }\n'
+        pnext_proc += '        prev_ext_struct = cur_ext_struct;\n\n'
+        pnext_proc += '        // Process the next structure in the chain\n'
+        pnext_proc += '        cur_pnext = header->pNext;\n'
+        pnext_proc += '    }\n'
+        pnext_proc += '    return head_pnext;\n'
+        pnext_proc += '}\n\n'
+        pnext_proc += '// Free a pNext extension chain\n'
+        pnext_proc += 'void FreeUnwrappedExtensionStructs(void *head) {\n'
+        pnext_proc += '    VkBaseOutStructure *curr_ptr = reinterpret_cast<VkBaseOutStructure *>(head);\n'
+        pnext_proc += '    while (curr_ptr) {\n'
+        pnext_proc += '        VkBaseOutStructure *header = curr_ptr;\n'
+        pnext_proc += '        curr_ptr = reinterpret_cast<VkBaseOutStructure *>(header->pNext);\n\n'
+        pnext_proc += '        switch (header->sType) {\n';
+        for item in self.pnext_extension_structs:
+            struct_info = self.struct_member_dict[item]
+            if struct_info[0].feature_protect is not None:
+                pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect
+            pnext_proc += '            case %s:\n' % self.structTypes[item].value
+            pnext_proc += '                delete reinterpret_cast<safe_%s *>(header);\n' % item
+            pnext_proc += '                break;\n'
+            if struct_info[0].feature_protect is not None:
+                pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect
+            pnext_proc += '\n'
+        pnext_proc += '            default:\n'
+        pnext_proc += '                assert(0);\n'
+        pnext_proc += '        }\n'
+        pnext_proc += '    }\n'
+        pnext_proc += '}\n'
+        return pnext_proc
+
+    #
+    # Generate source for creating a non-dispatchable object
+    def generate_create_ndo_code(self, indent, proto, params, cmd_info):
+        create_ndo_code = ''
+        handle_type = params[-1].find('type')
+        if self.isHandleTypeNonDispatchable(handle_type.text):
+            # Check for special case where multiple handles are returned
+            ndo_array = False
+            if cmd_info[-1].len is not None:
+                ndo_array = True;
+            handle_name = params[-1].find('name')
+            create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
+            indent = self.incIndent(indent)
+            create_ndo_code += '%sstd::lock_guard<std::mutex> lock(dispatch_lock);\n' % (indent)
+            ndo_dest = '*%s' % handle_name.text
+            if ndo_array == True:
+                create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len)
+                indent = self.incIndent(indent)
+                ndo_dest = '%s[index0]' % cmd_info[-1].name
+            create_ndo_code += '%s%s = layer_data->WrapNew(%s);\n' % (indent, ndo_dest, ndo_dest)
+            if ndo_array == True:
+                indent = self.decIndent(indent)
+                create_ndo_code += '%s}\n' % indent
+            indent = self.decIndent(indent)
+            create_ndo_code += '%s}\n' % (indent)
+        return create_ndo_code
+    #
+    # Generate source for destroying a non-dispatchable object
+    def generate_destroy_ndo_code(self, indent, proto, cmd_info):
+        destroy_ndo_code = ''
+        ndo_array = False
+        if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free']]:
+            # Check for special case where multiple handles are returned
+            if cmd_info[-1].len is not None:
+                ndo_array = True;
+                param = -1
+            else:
+                param = -2
+            if self.isHandleTypeNonDispatchable(cmd_info[param].type) == True:
+                if ndo_array == True:
+                    # This API is freeing an array of handles.  Remove them from the unique_id map.
+                    destroy_ndo_code += '%sif ((VK_SUCCESS == result) && (%s)) {\n' % (indent, cmd_info[param].name)
+                    indent = self.incIndent(indent)
+                    destroy_ndo_code += '%sstd::unique_lock<std::mutex> lock(dispatch_lock);\n' % (indent)
+                    destroy_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[param].len)
+                    indent = self.incIndent(indent)
+                    destroy_ndo_code += '%s%s handle = %s[index0];\n' % (indent, cmd_info[param].type, cmd_info[param].name)
+                    destroy_ndo_code += '%suint64_t unique_id = reinterpret_cast<uint64_t &>(handle);\n' % (indent)
+                    destroy_ndo_code += '%sunique_id_mapping.erase(unique_id);\n' % (indent)
+                    indent = self.decIndent(indent);
+                    destroy_ndo_code += '%s}\n' % indent
+                    indent = self.decIndent(indent);
+                    destroy_ndo_code += '%s}\n' % indent
+                else:
+                    # Remove a single handle from the map
+                    destroy_ndo_code += '%sstd::unique_lock<std::mutex> lock(dispatch_lock);\n' % (indent)
+                    destroy_ndo_code += '%suint64_t %s_id = reinterpret_cast<uint64_t &>(%s);\n' % (indent, cmd_info[param].name, cmd_info[param].name)
+                    destroy_ndo_code += '%s%s = (%s)unique_id_mapping[%s_id];\n' % (indent, cmd_info[param].name, cmd_info[param].type, cmd_info[param].name)
+                    destroy_ndo_code += '%sunique_id_mapping.erase(%s_id);\n' % (indent, cmd_info[param].name)
+                    destroy_ndo_code += '%slock.unlock();\n' % (indent)
+        return ndo_array, destroy_ndo_code
+
+    #
+    # Clean up local declarations
+    def cleanUpLocalDeclarations(self, indent, prefix, name, len, index, process_pnext):
+        cleanup = '%sif (local_%s%s) {\n' % (indent, prefix, name)
+        if len is not None:
+            if process_pnext:
+                cleanup += '%s    for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, len, index)
+                cleanup += '%s        FreeUnwrappedExtensionStructs(const_cast<void *>(local_%s%s[%s].pNext));\n' % (indent, prefix, name, index)
+                cleanup += '%s    }\n' % indent
+            cleanup += '%s    delete[] local_%s%s;\n' % (indent, prefix, name)
+        else:
+            if process_pnext:
+                cleanup += '%s    FreeUnwrappedExtensionStructs(const_cast<void *>(local_%s%s->pNext));\n' % (indent, prefix, name)
+            cleanup += '%s    delete local_%s%s;\n' % (indent, prefix, name)
+        cleanup += "%s}\n" % (indent)
+        return cleanup
+    #
+    # Output UO code for a single NDO (ndo_count is NULL) or a counted list of NDOs
+    def outputNDOs(self, ndo_type, ndo_name, ndo_count, prefix, index, indent, destroy_func, destroy_array, top_level):
+        decl_code = ''
+        pre_call_code = ''
+        post_call_code = ''
+        if ndo_count is not None:
+            if top_level == True:
+                decl_code += '%s%s *local_%s%s = NULL;\n' % (indent, ndo_type, prefix, ndo_name)
+            pre_call_code += '%s    if (%s%s) {\n' % (indent, prefix, ndo_name)
+            indent = self.incIndent(indent)
+            if top_level == True:
+                pre_call_code += '%s    local_%s%s = new %s[%s];\n' % (indent, prefix, ndo_name, ndo_type, ndo_count)
+                pre_call_code += '%s    for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index)
+                indent = self.incIndent(indent)
+                pre_call_code += '%s    local_%s%s[%s] = layer_data->Unwrap(%s[%s]);\n' % (indent, prefix, ndo_name, index, ndo_name, index)
+            else:
+                pre_call_code += '%s    for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index)
+                indent = self.incIndent(indent)
+                pre_call_code += '%s    %s%s[%s] = layer_data->Unwrap(%s%s[%s]);\n' % (indent, prefix, ndo_name, index, prefix, ndo_name, index)
+            indent = self.decIndent(indent)
+            pre_call_code += '%s    }\n' % indent
+            indent = self.decIndent(indent)
+            pre_call_code += '%s    }\n' % indent
+            if top_level == True:
+                post_call_code += '%sif (local_%s%s)\n' % (indent, prefix, ndo_name)
+                indent = self.incIndent(indent)
+                post_call_code += '%sdelete[] local_%s;\n' % (indent, ndo_name)
+        else:
+            if top_level == True:
+                if (destroy_func == False) or (destroy_array == True):
+                    pre_call_code += '%s    %s = layer_data->Unwrap(%s);\n' % (indent, ndo_name, ndo_name)
+            else:
+                # Make temp copy of this var with the 'local' removed. It may be better to not pass in 'local_'
+                # as part of the string and explicitly print it
+                fix = str(prefix).strip('local_');
+                pre_call_code += '%s    if (%s%s) {\n' % (indent, fix, ndo_name)
+                indent = self.incIndent(indent)
+                pre_call_code += '%s    %s%s = layer_data->Unwrap(%s%s);\n' % (indent, prefix, ndo_name, fix, ndo_name)
+                indent = self.decIndent(indent)
+                pre_call_code += '%s    }\n' % indent
+        return decl_code, pre_call_code, post_call_code
+    #
+    # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
+    # create_func means that this is API creates or allocates NDOs
+    # destroy_func indicates that this API destroys or frees NDOs
+    # destroy_array means that the destroy_func operated on an array of NDOs
+    def uniquify_members(self, members, indent, prefix, array_index, create_func, destroy_func, destroy_array, first_level_param):
+        decls = ''
+        pre_code = ''
+        post_code = ''
+        index = 'index%s' % str(array_index)
+        array_index += 1
+        # Process any NDOs in this structure and recurse for any sub-structs in this struct
+        for member in members:
+            process_pnext = self.StructWithExtensions(member.type)
+            # Handle NDOs
+            if self.isHandleTypeNonDispatchable(member.type) == True:
+                count_name = member.len
+                if (count_name is not None):
+                    if first_level_param == False:
+                        count_name = '%s%s' % (prefix, member.len)
+
+                if (first_level_param == False) or (create_func == False) or (not '*' in member.cdecl):
+                    (tmp_decl, tmp_pre, tmp_post) = self.outputNDOs(member.type, member.name, count_name, prefix, index, indent, destroy_func, destroy_array, first_level_param)
+                    decls += tmp_decl
+                    pre_code += tmp_pre
+                    post_code += tmp_post
+            # Handle Structs that contain NDOs at some level
+            elif member.type in self.struct_member_dict:
+                # Structs at first level will have an NDO, OR, we need a safe_struct for the pnext chain
+                if self.struct_contains_ndo(member.type) == True or process_pnext:
+                    struct_info = self.struct_member_dict[member.type]
+                    # TODO (jbolz): Can this use paramIsPointer?
+                    ispointer = '*' in member.cdecl;
+                    # Struct Array
+                    if member.len is not None:
+                        # Update struct prefix
+                        if first_level_param == True:
+                            new_prefix = 'local_%s' % member.name
+                            # Declare safe_VarType for struct
+                            decls += '%ssafe_%s *%s = NULL;\n' % (indent, member.type, new_prefix)
+                        else:
+                            new_prefix = '%s%s' % (prefix, member.name)
+                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
+                        indent = self.incIndent(indent)
+                        if first_level_param == True:
+                            pre_code += '%s    %s = new safe_%s[%s];\n' % (indent, new_prefix, member.type, member.len)
+                        pre_code += '%s    for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index)
+                        indent = self.incIndent(indent)
+                        if first_level_param == True:
+                            pre_code += '%s    %s[%s].initialize(&%s[%s]);\n' % (indent, new_prefix, index, member.name, index)
+                            if process_pnext:
+                                pre_code += '%s    %s[%s].pNext = CreateUnwrappedExtensionStructs(layer_data, %s[%s].pNext);\n' % (indent, new_prefix, index, new_prefix, index)
+                        local_prefix = '%s[%s].' % (new_prefix, index)
+                        # Process sub-structs in this struct
+                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, local_prefix, array_index, create_func, destroy_func, destroy_array, False)
+                        decls += tmp_decl
+                        pre_code += tmp_pre
+                        post_code += tmp_post
+                        indent = self.decIndent(indent)
+                        pre_code += '%s    }\n' % indent
+                        indent = self.decIndent(indent)
+                        pre_code += '%s    }\n' % indent
+                        if first_level_param == True:
+                            post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index, process_pnext)
+                    # Single Struct
+                    elif ispointer:
+                        # Update struct prefix
+                        if first_level_param == True:
+                            new_prefix = 'local_%s->' % member.name
+                            decls += '%ssafe_%s *local_%s%s = NULL;\n' % (indent, member.type, prefix, member.name)
+                        else:
+                            new_prefix = '%s%s->' % (prefix, member.name)
+                        # Declare safe_VarType for struct
+                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
+                        indent = self.incIndent(indent)
+                        if first_level_param == True:
+                            pre_code += '%s    local_%s%s = new safe_%s(%s);\n' % (indent, prefix, member.name, member.type, member.name)
+                        # Process sub-structs in this struct
+                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False)
+                        decls += tmp_decl
+                        pre_code += tmp_pre
+                        post_code += tmp_post
+                        if process_pnext:
+                            pre_code += '%s    local_%s%s->pNext = CreateUnwrappedExtensionStructs(layer_data, local_%s%s->pNext);\n' % (indent, prefix, member.name, prefix, member.name)
+                        indent = self.decIndent(indent)
+                        pre_code += '%s    }\n' % indent
+                        if first_level_param == True:
+                            post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index, process_pnext)
+                    else:
+                        # Update struct prefix
+                        if first_level_param == True:
+                            sys.exit(1)
+                        else:
+                            new_prefix = '%s%s.' % (prefix, member.name)
+                        # Process sub-structs in this struct
+                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False)
+                        decls += tmp_decl
+                        pre_code += tmp_pre
+                        post_code += tmp_post
+                        if process_pnext:
+                            pre_code += '%s    local_%s%s.pNext = CreateUnwrappedExtensionStructs(layer_data, local_%s%s.pNext);\n' % (indent, prefix, member.name, prefix, member.name)
+        return decls, pre_code, post_code
+    #
+    # For a particular API, generate the non-dispatchable-object wrapping/unwrapping code
+    def generate_wrapping_code(self, cmd):
+        indent = '    '
+        proto = cmd.find('proto/name')
+        params = cmd.findall('param')
+
+        if proto.text is not None:
+            cmd_member_dict = dict(self.cmdMembers)
+            cmd_info = cmd_member_dict[proto.text]
+            # Handle ndo create/allocate operations
+            if cmd_info[0].iscreate:
+                create_ndo_code = self.generate_create_ndo_code(indent, proto, params, cmd_info)
+            else:
+                create_ndo_code = ''
+            # Handle ndo destroy/free operations
+            if cmd_info[0].isdestroy:
+                (destroy_array, destroy_ndo_code) = self.generate_destroy_ndo_code(indent, proto, cmd_info)
+            else:
+                destroy_array = False
+                destroy_ndo_code = ''
+            paramdecl = ''
+            param_pre_code = ''
+            param_post_code = ''
+            create_func = True if create_ndo_code else False
+            destroy_func = True if destroy_ndo_code else False
+            (paramdecl, param_pre_code, param_post_code) = self.uniquify_members(cmd_info, indent, '', 0, create_func, destroy_func, destroy_array, True)
+            param_post_code += create_ndo_code
+            if destroy_ndo_code:
+                if destroy_array == True:
+                    param_post_code += destroy_ndo_code
+                else:
+                    param_pre_code += destroy_ndo_code
+            if param_pre_code:
+                if (not destroy_func) or (destroy_array):
+                    param_pre_code = '%s{\n%s%s%s%s}\n' % ('    ', indent, self.lock_guard(indent), param_pre_code, indent)
+        return paramdecl, param_pre_code, param_post_code
+    #
+    # Capture command parameter info needed to wrap NDOs as well as handling some boilerplate code
+    def genCmd(self, cmdinfo, cmdname, alias):
+
+        # Add struct-member type information to command parameter information
+        OutputGenerator.genCmd(self, cmdinfo, cmdname, alias)
+        members = cmdinfo.elem.findall('.//param')
+        # Iterate over members once to get length parameters for arrays
+        lens = set()
+        for member in members:
+            len = self.getLen(member)
+            if len:
+                lens.add(len)
+        struct_member_dict = dict(self.structMembers)
+        # Generate member info
+        membersInfo = []
+        for member in members:
+            # Get type and name of member
+            info = self.getTypeNameTuple(member)
+            type = info[0]
+            name = info[1]
+            cdecl = self.makeCParamDecl(member, 0)
+            # Check for parameter name in lens set
+            iscount = True if name in lens else False
+            len = self.getLen(member)
+            isconst = True if 'const' in cdecl else False
+            ispointer = self.paramIsPointer(member)
+            # Mark param as local if it is an array of NDOs
+            islocal = False;
+            if self.isHandleTypeNonDispatchable(type) == True:
+                if (len is not None) and (isconst == True):
+                    islocal = True
+            # Or if it's a struct that contains an NDO
+            elif type in struct_member_dict:
+                if self.struct_contains_ndo(type) == True:
+                    islocal = True
+            isdestroy = True if True in [destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free']] else False
+            iscreate = True if True in [create_txt in cmdname for create_txt in ['Create', 'Allocate', 'GetRandROutputDisplayEXT', 'RegisterDeviceEvent', 'RegisterDisplayEvent']] else False
+            extstructs = self.registry.validextensionstructs[type] if name == 'pNext' else None
+            membersInfo.append(self.CommandParam(type=type,
+                                                 name=name,
+                                                 ispointer=ispointer,
+                                                 isconst=isconst,
+                                                 iscount=iscount,
+                                                 len=len,
+                                                 extstructs=extstructs,
+                                                 cdecl=cdecl,
+                                                 islocal=islocal,
+                                                 iscreate=iscreate,
+                                                 isdestroy=isdestroy,
+                                                 feature_protect=self.featureExtraProtect))
+        self.cmdMembers.append(self.CmdMemberData(name=cmdname, members=membersInfo))
+        self.cmd_info_data.append(self.CmdInfoData(name=cmdname, cmdinfo=cmdinfo))
+        self.cmd_feature_protect.append(self.CmdExtraProtect(name=cmdname, extra_protect=self.featureExtraProtect))
+    #
+    # Create prototype for dispatch header file
+    def GenDispatchFunctionPrototype(self, cmdinfo, ifdef_text):
+        decls = self.makeCDecls(cmdinfo.elem)
+        func_sig = decls[0][:-1]
+        func_sig = func_sig.replace("VKAPI_ATTR ", "")
+        func_sig = func_sig.replace("VKAPI_CALL ", "Dispatch")
+        func_sig = func_sig.replace("(", "(ValidationObject *layer_data, ")
+        func_sig += ';'
+        dispatch_prototype = ''
+        if ifdef_text is not None:
+            dispatch_prototype = '#ifdef %s\n' % ifdef_text
+        dispatch_prototype += func_sig
+        if ifdef_text is not None:
+            dispatch_prototype += '\n#endif // %s' % ifdef_text
+        return dispatch_prototype
+    #
+    # Create code to wrap NDOs as well as handling some boilerplate code
+    def WrapCommands(self):
+        cmd_member_dict = dict(self.cmdMembers)
+        cmd_info_dict = dict(self.cmd_info_data)
+        cmd_protect_dict = dict(self.cmd_feature_protect)
+
+        for api_call in self.cmdMembers:
+            cmdname = api_call.name
+            cmdinfo = cmd_info_dict[api_call.name]
+            feature_extra_protect = cmd_protect_dict[api_call.name]
+
+            # Add fuction prototype to header data
+            self.appendSection('header_file', self.GenDispatchFunctionPrototype(cmdinfo, feature_extra_protect))
+
+            if cmdname in self.no_autogen_list:
+                decls = self.makeCDecls(cmdinfo.elem)
+                self.appendSection('source_file', '')
+                self.appendSection('source_file', '// Skip %s dispatch, manually generated' % cmdname)
+                continue
+
+            # Generate NDO wrapping/unwrapping code for all parameters
+            (api_decls, api_pre, api_post) = self.generate_wrapping_code(cmdinfo.elem)
+            # If API doesn't contain NDO's, we still need to make a down-chain call
+            down_chain_call_only = False
+            if not api_decls and not api_pre and not api_post:
+                down_chain_call_only = True
+            if (feature_extra_protect is not None):
+                self.appendSection('source_file', '')
+                self.appendSection('source_file', '#ifdef ' + feature_extra_protect)
+
+            decls = self.makeCDecls(cmdinfo.elem)
+            func_sig = decls[0][:-1]
+            func_sig = func_sig.replace("VKAPI_ATTR ", "")
+            func_sig = func_sig.replace("VKAPI_CALL ", "Dispatch")
+            func_sig = func_sig.replace("(", "(ValidationObject *layer_data, ")
+            self.appendSection('source_file', '')
+            self.appendSection('source_file', func_sig)
+            self.appendSection('source_file', '{')
+            # Setup common to call wrappers, first parameter is always dispatchable
+            dispatchable_type = cmdinfo.elem.find('param/type').text
+            dispatchable_name = cmdinfo.elem.find('param/name').text
+
+            # Gather the parameter items
+            params = cmdinfo.elem.findall('param/name')
+            # Pull out the text for each of the parameters, separate them by commas in a list
+            paramstext = ', '.join([str(param.text) for param in params])
+            wrapped_paramstext = paramstext
+            # If any of these paramters has been replaced by a local var, fix up the list
+            params = cmd_member_dict[cmdname]
+            for param in params:
+                if param.islocal == True or self.StructWithExtensions(param.type):
+                    if param.ispointer == True:
+                        wrapped_paramstext = wrapped_paramstext.replace(param.name, '(%s %s*)local_%s' % ('const', param.type, param.name))
+                    else:
+                        wrapped_paramstext = wrapped_paramstext.replace(param.name, '(%s %s)local_%s' % ('const', param.type, param.name))
+
+            # First, add check and down-chain call. Use correct dispatch table
+            dispatch_table_type = "device_dispatch_table"
+            if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]:
+                dispatch_table_type = "instance_dispatch_table"
+
+            api_func = cmdinfo.elem.attrib.get('name').replace('vk','layer_data->%s.',1) % dispatch_table_type
+
+            # Put all this together for the final down-chain call
+            if not down_chain_call_only:
+                unwrapped_dispatch_call = api_func + '(' + paramstext + ')'
+                self.appendSection('source_file', '    if (!wrap_handles) return %s;' % unwrapped_dispatch_call)
+
+            # Handle return values, if any
+            resulttype = cmdinfo.elem.find('proto/type')
+            if (resulttype is not None and resulttype.text == 'void'):
+              resulttype = None
+            if (resulttype is not None):
+                assignresult = resulttype.text + ' result = '
+            else:
+                assignresult = ''
+            # Pre-pend declarations and pre-api-call codegen
+            if api_decls:
+                self.appendSection('source_file', "\n".join(str(api_decls).rstrip().split("\n")))
+            if api_pre:
+                self.appendSection('source_file', "\n".join(str(api_pre).rstrip().split("\n")))
+            # Generate the wrapped dispatch call 
+            self.appendSection('source_file', '    ' + assignresult + api_func + '(' + wrapped_paramstext + ');')
+
+            # And add the post-API-call codegen
+            self.appendSection('source_file', "\n".join(str(api_post).rstrip().split("\n")))
+            # Handle the return result variable, if any
+            if (resulttype is not None):
+                self.appendSection('source_file', '    return result;')
+            self.appendSection('source_file', '}')
+            if (feature_extra_protect is not None):
+                self.appendSection('source_file', '#endif // '+ feature_extra_protect)
+
diff --git a/scripts/layer_chassis_generator.py b/scripts/layer_chassis_generator.py
new file mode 100644
index 0000000..87c1a1f
--- /dev/null
+++ b/scripts/layer_chassis_generator.py
@@ -0,0 +1,1564 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Tobin Ehlis <tobine@google.com>
+# Author: Mark Lobodzinski <mark@lunarg.com>
+#
+# This script generates the dispatch portion of a factory layer which intercepts
+# all Vulkan  functions. The resultant factory layer allows rapid development of
+# layers and interceptors.
+
+import os,re,sys
+from generator import *
+from common_codegen import *
+
+# LayerFactoryGeneratorOptions - subclass of GeneratorOptions.
+#
+# Adds options used by LayerFactoryOutputGenerator objects during factory
+# layer generation.
+#
+# Additional members
+#   prefixText - list of strings to prefix generated header with
+#     (usually a copyright statement + calling convention macros).
+#   protectFile - True if multiple inclusion protection should be
+#     generated (based on the filename) around the entire header.
+#   protectFeature - True if #ifndef..#endif protection should be
+#     generated around a feature interface in the header file.
+#   genFuncPointers - True if function pointer typedefs should be
+#     generated
+#   protectProto - If conditional protection should be generated
+#     around prototype declarations, set to either '#ifdef'
+#     to require opt-in (#ifdef protectProtoStr) or '#ifndef'
+#     to require opt-out (#ifndef protectProtoStr). Otherwise
+#     set to None.
+#   protectProtoStr - #ifdef/#ifndef symbol to use around prototype
+#     declarations, if protectProto is set
+#   apicall - string to use for the function declaration prefix,
+#     such as APICALL on Windows.
+#   apientry - string to use for the calling convention macro,
+#     in typedefs, such as APIENTRY.
+#   apientryp - string to use for the calling convention macro
+#     in function pointer typedefs, such as APIENTRYP.
+#   indentFuncProto - True if prototype declarations should put each
+#     parameter on a separate line
+#   indentFuncPointer - True if typedefed function pointers should put each
+#     parameter on a separate line
+#   alignFuncParam - if nonzero and parameters are being put on a
+#     separate line, align parameter names at the specified column
+class LayerChassisGeneratorOptions(GeneratorOptions):
+    def __init__(self,
+                 filename = None,
+                 directory = '.',
+                 apiname = None,
+                 profile = None,
+                 versions = '.*',
+                 emitversions = '.*',
+                 defaultExtensions = None,
+                 addExtensions = None,
+                 removeExtensions = None,
+                 emitExtensions = None,
+                 sortProcedure = regSortFeatures,
+                 prefixText = "",
+                 genFuncPointers = True,
+                 protectFile = True,
+                 protectFeature = True,
+                 apicall = '',
+                 apientry = '',
+                 apientryp = '',
+                 indentFuncProto = True,
+                 indentFuncPointer = False,
+                 alignFuncParam = 0,
+                 helper_file_type = '',
+                 expandEnumerants = True):
+        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
+                                  versions, emitversions, defaultExtensions,
+                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        self.prefixText      = prefixText
+        self.genFuncPointers = genFuncPointers
+        self.protectFile     = protectFile
+        self.protectFeature  = protectFeature
+        self.apicall         = apicall
+        self.apientry        = apientry
+        self.apientryp       = apientryp
+        self.indentFuncProto = indentFuncProto
+        self.indentFuncPointer = indentFuncPointer
+        self.alignFuncParam  = alignFuncParam
+
+# LayerChassisOutputGenerator - subclass of OutputGenerator.
+# Generates a LayerFactory layer that intercepts all API entrypoints
+#  This is intended to be used as a starting point for creating custom layers
+#
+# ---- methods ----
+# LayerChassisOutputGenerator(errFile, warnFile, diagFile) - args as for
+#   OutputGenerator. Defines additional internal state.
+# ---- methods overriding base class ----
+# beginFile(genOpts)
+# endFile()
+# beginFeature(interface, emit)
+# endFeature()
+# genType(typeinfo,name)
+# genStruct(typeinfo,name)
+# genGroup(groupinfo,name)
+# genEnum(enuminfo, name)
+# genCmd(cmdinfo)
+class LayerChassisOutputGenerator(OutputGenerator):
+    """Generate specified API interfaces in a specific style, such as a C header"""
+    # This is an ordered list of sections in the header file.
+    TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
+                     'group', 'bitmask', 'funcpointer', 'struct']
+    ALL_SECTIONS = TYPE_SECTIONS + ['command']
+
+    manual_functions = [
+        # Include functions here to be interecpted w/ manually implemented function bodies
+        'vkGetDeviceProcAddr',
+        'vkGetInstanceProcAddr',
+        'vkGetPhysicalDeviceProcAddr',
+        'vkCreateDevice',
+        'vkDestroyDevice',
+        'vkCreateInstance',
+        'vkDestroyInstance',
+        'vkEnumerateInstanceLayerProperties',
+        'vkEnumerateInstanceExtensionProperties',
+        'vkEnumerateDeviceLayerProperties',
+        'vkEnumerateDeviceExtensionProperties',
+        # Functions that are handled explicitly due to chassis architecture violations
+        'vkCreateGraphicsPipelines',
+        'vkCreateComputePipelines',
+        'vkCreateRayTracingPipelinesNV',
+        'vkCreatePipelineLayout',
+        'vkCreateShaderModule',
+        'vkAllocateDescriptorSets',
+        # ValidationCache functions do not get dispatched
+        'vkCreateValidationCacheEXT',
+        'vkDestroyValidationCacheEXT',
+        'vkMergeValidationCachesEXT',
+        'vkGetValidationCacheDataEXT',
+        ]
+
+    alt_ret_codes = [
+        # Include functions here which must tolerate VK_INCOMPLETE as a return code
+        'vkEnumeratePhysicalDevices',
+        'vkEnumeratePhysicalDeviceGroupsKHR',
+        'vkGetValidationCacheDataEXT',
+        'vkGetPipelineCacheData',
+        'vkGetShaderInfoAMD',
+        'vkGetPhysicalDeviceDisplayPropertiesKHR',
+        'vkGetPhysicalDeviceDisplayProperties2KHR',
+        'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
+        'vkGetDisplayPlaneSupportedDisplaysKHR',
+        'vkGetDisplayModePropertiesKHR',
+        'vkGetDisplayModeProperties2KHR',
+        'vkGetPhysicalDeviceSurfaceFormatsKHR',
+        'vkGetPhysicalDeviceSurfacePresentModesKHR',
+        'vkGetPhysicalDevicePresentRectanglesKHR',
+        'vkGetPastPresentationTimingGOOGLE',
+        'vkGetSwapchainImagesKHR',
+        'vkEnumerateInstanceLayerProperties',
+        'vkEnumerateDeviceLayerProperties',
+        'vkEnumerateInstanceExtensionProperties',
+        'vkEnumerateDeviceExtensionProperties',
+        'vkGetPhysicalDeviceCalibrateableTimeDomainsEXT',
+    ]
+
+    pre_dispatch_debug_utils_functions = {
+        'vkDebugMarkerSetObjectNameEXT' : 'layer_data->report_data->DebugReportSetMarkerObjectName(pNameInfo);',
+        'vkSetDebugUtilsObjectNameEXT' : 'layer_data->report_data->DebugReportSetUtilsObjectName(pNameInfo);',
+        'vkQueueBeginDebugUtilsLabelEXT' : 'BeginQueueDebugUtilsLabel(layer_data->report_data, queue, pLabelInfo);',
+        'vkQueueInsertDebugUtilsLabelEXT' : 'InsertQueueDebugUtilsLabel(layer_data->report_data, queue, pLabelInfo);',
+        'vkCmdBeginDebugUtilsLabelEXT' : 'BeginCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);',
+        'vkCmdInsertDebugUtilsLabelEXT' : 'InsertCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);'
+        }
+
+    post_dispatch_debug_utils_functions = {
+        'vkQueueEndDebugUtilsLabelEXT' : 'EndQueueDebugUtilsLabel(layer_data->report_data, queue);',
+        'vkCmdEndDebugUtilsLabelEXT' : 'EndCmdDebugUtilsLabel(layer_data->report_data, commandBuffer);',
+        'vkCmdInsertDebugUtilsLabelEXT' : 'InsertCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);',
+        'vkCreateDebugReportCallbackEXT' : 'layer_create_report_callback(layer_data->report_data, false, pCreateInfo, pAllocator, pCallback);',
+        'vkDestroyDebugReportCallbackEXT' : 'layer_destroy_report_callback(layer_data->report_data, callback, pAllocator);',
+        'vkCreateDebugUtilsMessengerEXT' : 'layer_create_messenger_callback(layer_data->report_data, false, pCreateInfo, pAllocator, pMessenger);',
+        'vkDestroyDebugUtilsMessengerEXT' : 'layer_destroy_messenger_callback(layer_data->report_data, messenger, pAllocator);',
+        }
+
+    precallvalidate_loop = "for (auto intercept : layer_data->object_dispatch) {"
+    precallrecord_loop = precallvalidate_loop
+    postcallrecord_loop = "for (auto intercept : layer_data->object_dispatch) {"
+
+    inline_custom_header_preamble = """
+#define NOMINMAX
+#include <mutex>
+#include <cinttypes>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unordered_map>
+#include <unordered_set>
+#include <algorithm>
+#include <memory>
+
+#include "vk_loader_platform.h"
+#include "vulkan/vulkan.h"
+#include "vk_layer_config.h"
+#include "vk_layer_data.h"
+#include "vk_layer_logging.h"
+#include "vk_object_types.h"
+#include "vulkan/vk_layer.h"
+#include "vk_enum_string_helper.h"
+#include "vk_layer_extension_utils.h"
+#include "vk_layer_utils.h"
+#include "vulkan/vk_layer.h"
+#include "vk_dispatch_table_helper.h"
+#include "vk_validation_error_messages.h"
+#include "vk_extension_helper.h"
+#include "vk_safe_struct.h"
+#include "vk_typemap_helper.h"
+
+
+extern uint64_t global_unique_id;
+extern std::unordered_map<uint64_t, uint64_t> unique_id_mapping;
+"""
+
+    inline_custom_header_class_definition = """
+
+// Layer object type identifiers
+enum LayerObjectTypeId {
+    LayerObjectTypeInstance,                    // Container for an instance dispatch object
+    LayerObjectTypeDevice,                      // Container for a device dispatch object
+    LayerObjectTypeThreading,                   // Instance or device threading layer object
+    LayerObjectTypeParameterValidation,         // Instance or device parameter validation layer object
+    LayerObjectTypeObjectTracker,               // Instance or device object tracker layer object
+    LayerObjectTypeCoreValidation,              // Instance or device core validation layer object
+};
+
+struct TEMPLATE_STATE {
+    VkDescriptorUpdateTemplateKHR desc_update_template;
+    safe_VkDescriptorUpdateTemplateCreateInfo create_info;
+
+    TEMPLATE_STATE(VkDescriptorUpdateTemplateKHR update_template, safe_VkDescriptorUpdateTemplateCreateInfo *pCreateInfo)
+        : desc_update_template(update_template), create_info(*pCreateInfo) {}
+};
+
+class LAYER_PHYS_DEV_PROPERTIES {
+public:
+    VkPhysicalDeviceProperties properties;
+    std::vector<VkQueueFamilyProperties> queue_family_properties;
+};
+
+// CHECK_DISABLED struct is a container for bools that can block validation checks from being performed.
+// The end goal is to have all checks guarded by a bool. The bools are all "false" by default meaning that all checks
+// are enabled. At CreateInstance time, the user can use the VK_EXT_validation_flags extension to pass in enum values
+// of VkValidationCheckEXT that will selectively disable checks.
+// The VK_EXT_validation_features extension can also be used with the VkValidationFeaturesEXT structure to set
+// disables in the CHECK_DISABLED struct and/or enables in the CHECK_ENABLED struct.
+struct CHECK_DISABLED {
+    bool command_buffer_state;
+    bool create_descriptor_set_layout;
+    bool destroy_buffer_view;       // Skip validation at DestroyBufferView time
+    bool destroy_image_view;        // Skip validation at DestroyImageView time
+    bool destroy_pipeline;          // Skip validation at DestroyPipeline time
+    bool destroy_descriptor_pool;   // Skip validation at DestroyDescriptorPool time
+    bool destroy_framebuffer;       // Skip validation at DestroyFramebuffer time
+    bool destroy_renderpass;        // Skip validation at DestroyRenderpass time
+    bool destroy_image;             // Skip validation at DestroyImage time
+    bool destroy_sampler;           // Skip validation at DestroySampler time
+    bool destroy_command_pool;      // Skip validation at DestroyCommandPool time
+    bool destroy_event;             // Skip validation at DestroyEvent time
+    bool free_memory;               // Skip validation at FreeMemory time
+    bool object_in_use;             // Skip all object in_use checking
+    bool idle_descriptor_set;       // Skip check to verify that descriptor set is no in-use
+    bool push_constant_range;       // Skip push constant range checks
+    bool free_descriptor_sets;      // Skip validation prior to vkFreeDescriptorSets()
+    bool allocate_descriptor_sets;  // Skip validation prior to vkAllocateDescriptorSets()
+    bool update_descriptor_sets;    // Skip validation prior to vkUpdateDescriptorSets()
+    bool wait_for_fences;
+    bool get_fence_state;
+    bool queue_wait_idle;
+    bool device_wait_idle;
+    bool destroy_fence;
+    bool destroy_semaphore;
+    bool destroy_query_pool;
+    bool get_query_pool_results;
+    bool destroy_buffer;
+    bool shader_validation;  // Skip validation for shaders
+
+    void SetAll(bool value) { std::fill(&command_buffer_state, &shader_validation + 1, value); }
+};
+
+struct CHECK_ENABLED {
+    bool gpu_validation;
+    bool gpu_validation_reserve_binding_slot;
+
+    void SetAll(bool value) { std::fill(&gpu_validation, &gpu_validation_reserve_binding_slot + 1, value); }
+};
+
+// Layer chassis validation object base class definition
+class ValidationObject {
+    public:
+        uint32_t api_version;
+        debug_report_data* report_data = nullptr;
+        std::vector<VkDebugReportCallbackEXT> logging_callback;
+        std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
+
+        VkLayerInstanceDispatchTable instance_dispatch_table;
+        VkLayerDispatchTable device_dispatch_table;
+
+        InstanceExtensions instance_extensions;
+        DeviceExtensions device_extensions = {};
+        CHECK_DISABLED disabled = {};
+        CHECK_ENABLED enabled = {};
+
+        VkInstance instance = VK_NULL_HANDLE;
+        VkPhysicalDevice physical_device = VK_NULL_HANDLE;
+        VkDevice device = VK_NULL_HANDLE;
+        LAYER_PHYS_DEV_PROPERTIES phys_dev_properties = {};
+
+        std::vector<ValidationObject*> object_dispatch;
+        LayerObjectTypeId container_type;
+
+        std::string layer_name = "CHASSIS";
+
+        // Constructor
+        ValidationObject(){};
+        // Destructor
+        virtual ~ValidationObject() {};
+
+        std::mutex validation_object_mutex;
+        virtual std::unique_lock<std::mutex> write_lock() {
+            return std::unique_lock<std::mutex>(validation_object_mutex);
+        }
+
+        ValidationObject* GetValidationObject(std::vector<ValidationObject*>& object_dispatch, LayerObjectTypeId object_type) {
+            for (auto validation_object : object_dispatch) {
+                if (validation_object->container_type == object_type) {
+                    return validation_object;
+                }
+            }
+            return nullptr;
+        };
+
+        // Handle Wrapping Data
+        // Reverse map display handles
+        std::unordered_map<VkDisplayKHR, uint64_t> display_id_reverse_mapping;
+        std::unordered_map<uint64_t, std::unique_ptr<TEMPLATE_STATE>> desc_template_map;
+        struct SubpassesUsageStates {
+            std::unordered_set<uint32_t> subpasses_using_color_attachment;
+            std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
+        };
+        // Uses unwrapped handles
+        std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
+        // Map of wrapped swapchain handles to arrays of wrapped swapchain image IDs
+        // Each swapchain has an immutable list of wrapped swapchain image IDs -- always return these IDs if they exist
+        std::unordered_map<VkSwapchainKHR, std::vector<VkImage>> swapchain_wrapped_image_handle_map;
+        // Map of wrapped descriptor pools to set of wrapped descriptor sets allocated from each pool
+        std::unordered_map<VkDescriptorPool, std::unordered_set<VkDescriptorSet>> pool_descriptor_sets_map;
+
+
+        // Unwrap a handle.  Must hold lock.
+        template <typename HandleType>
+        HandleType Unwrap(HandleType wrappedHandle) {
+            // TODO: don't use operator[] here.
+            return (HandleType)unique_id_mapping[reinterpret_cast<uint64_t const &>(wrappedHandle)];
+        }
+
+        // Wrap a newly created handle with a new unique ID, and return the new ID -- must hold lock.
+        template <typename HandleType>
+        HandleType WrapNew(HandleType newlyCreatedHandle) {
+            auto unique_id = global_unique_id++;
+            unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
+            return (HandleType)unique_id;
+        }
+
+        // Specialized handling for VkDisplayKHR. Adds an entry to enable reverse-lookup. Must hold lock.
+        VkDisplayKHR WrapDisplay(VkDisplayKHR newlyCreatedHandle, ValidationObject *map_data) {
+            auto unique_id = global_unique_id++;
+            unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
+            map_data->display_id_reverse_mapping[newlyCreatedHandle] = unique_id;
+            return (VkDisplayKHR)unique_id;
+        }
+
+        // VkDisplayKHR objects don't have a single point of creation, so we need to see if one already exists in the map before
+        // creating another. Must hold lock.
+        VkDisplayKHR MaybeWrapDisplay(VkDisplayKHR handle, ValidationObject *map_data) {
+            // See if this display is already known
+            auto it = map_data->display_id_reverse_mapping.find(handle);
+            if (it != map_data->display_id_reverse_mapping.end()) return (VkDisplayKHR)it->second;
+            // Unknown, so wrap
+            return WrapDisplay(handle, map_data);
+        }
+
+        // Pre/post hook point declarations
+"""
+
+    inline_copyright_message = """
+// This file is ***GENERATED***.  Do Not Edit.
+// See layer_chassis_generator.py for modifications.
+
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (c) 2015-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ */"""
+
+    inline_custom_source_preamble = """
+
+#include <string.h>
+#include <mutex>
+
+#define VALIDATION_ERROR_MAP_IMPL
+
+#include "chassis.h"
+#include "layer_chassis_dispatch.h"
+
+std::unordered_map<void*, ValidationObject*> layer_data_map;
+
+// Global unique object identifier.  All increments must be guarded by a lock.
+uint64_t global_unique_id = 1;
+// Map uniqueID to actual object handle
+std::unordered_map<uint64_t, uint64_t> unique_id_mapping;
+
+// TODO: This variable controls handle wrapping -- in the future it should be hooked
+//       up to the new VALIDATION_FEATURES extension. Temporarily, control with a compile-time flag.
+#if defined(LAYER_CHASSIS_CAN_WRAP_HANDLES)
+bool wrap_handles = true;
+#else
+const bool wrap_handles = false;
+#endif
+
+// Include child object (layer) definitions
+#if BUILD_OBJECT_TRACKER
+#include "object_lifetime_validation.h"
+#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_object_tracker"
+#elif BUILD_THREAD_SAFETY
+#include "thread_safety.h"
+#define OBJECT_LAYER_NAME "VK_LAYER_GOOGLE_threading"
+#elif BUILD_PARAMETER_VALIDATION
+#include "stateless_validation.h"
+#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_parameter_validation"
+#elif BUILD_CORE_VALIDATION
+#include "core_validation.h"
+#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_core_validation"
+#else
+#define OBJECT_LAYER_NAME "VK_LAYER_GOOGLE_unique_objects"
+#endif
+
+namespace vulkan_layer_chassis {
+
+using std::unordered_map;
+
+static const VkLayerProperties global_layer = {
+    OBJECT_LAYER_NAME, VK_LAYER_API_VERSION, 1, "LunarG validation Layer",
+};
+
+static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
+
+extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
+
+
+// Manually written functions
+
+// Check enabled instance extensions against supported instance extension whitelist
+static void InstanceExtensionWhitelist(ValidationObject *layer_data, const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
+    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+        // Check for recognized instance extensions
+        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kInstanceExtensionNames)) {
+            log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                    kVUIDUndefined,
+                    "Instance Extension %s is not supported by this layer.  Using this extension may adversely affect validation "
+                    "results and/or produce undefined behavior.",
+                    pCreateInfo->ppEnabledExtensionNames[i]);
+        }
+    }
+}
+
+// Check enabled device extensions against supported device extension whitelist
+static void DeviceExtensionWhitelist(ValidationObject *layer_data, const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
+    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+        // Check for recognized device extensions
+        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kDeviceExtensionNames)) {
+            log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                    kVUIDUndefined,
+                    "Device Extension %s is not supported by this layer.  Using this extension may adversely affect validation "
+                    "results and/or produce undefined behavior.",
+                    pCreateInfo->ppEnabledExtensionNames[i]);
+        }
+    }
+}
+
+// For the given ValidationCheck enum, set all relevant instance disabled flags to true
+void SetDisabledFlags(ValidationObject *instance_data, const VkValidationFlagsEXT *val_flags_struct) {
+    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
+        switch (val_flags_struct->pDisabledValidationChecks[i]) {
+        case VK_VALIDATION_CHECK_SHADERS_EXT:
+            instance_data->disabled.shader_validation = true;
+            break;
+        case VK_VALIDATION_CHECK_ALL_EXT:
+            // Set all disabled flags to true
+            instance_data->disabled.SetAll(true);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void SetValidationFeatures(ValidationObject *instance_data, const VkValidationFeaturesEXT *val_features_struct) {
+    for (uint32_t i = 0; i < val_features_struct->disabledValidationFeatureCount; ++i) {
+        switch (val_features_struct->pDisabledValidationFeatures[i]) {
+        case VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT:
+            instance_data->disabled.shader_validation = true;
+            break;
+        case VK_VALIDATION_FEATURE_DISABLE_ALL_EXT:
+            // Set all disabled flags to true
+            instance_data->disabled.SetAll(true);
+            break;
+        default:
+            break;
+        }
+    }
+    for (uint32_t i = 0; i < val_features_struct->enabledValidationFeatureCount; ++i) {
+        switch (val_features_struct->pEnabledValidationFeatures[i]) {
+        case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT:
+            instance_data->enabled.gpu_validation = true;
+            break;
+        case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT:
+            instance_data->enabled.gpu_validation_reserve_binding_slot = true;
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (!ApiParentExtensionEnabled(funcName, layer_data->device_extensions.device_extension_set)) {
+        return nullptr;
+    }
+    const auto &item = name_to_funcptr_map.find(funcName);
+    if (item != name_to_funcptr_map.end()) {
+        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+    }
+    auto &table = layer_data->device_dispatch_table;
+    if (!table.GetDeviceProcAddr) return nullptr;
+    return table.GetDeviceProcAddr(device, funcName);
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
+    const auto &item = name_to_funcptr_map.find(funcName);
+    if (item != name_to_funcptr_map.end()) {
+        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+    }
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    auto &table = layer_data->instance_dispatch_table;
+    if (!table.GetInstanceProcAddr) return nullptr;
+    return table.GetInstanceProcAddr(instance, funcName);
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    auto &table = layer_data->instance_dispatch_table;
+    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
+    return table.GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
+    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
+                                                              VkLayerProperties *pProperties) {
+    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
+                                                                    VkExtensionProperties *pProperties) {
+    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
+        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
+
+    return VK_ERROR_LAYER_NOT_PRESENT;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
+                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
+    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
+    assert(physicalDevice);
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
+    return layer_data->instance_dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
+                                              VkInstance *pInstance) {
+    VkLayerInstanceCreateInfo* chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
+
+    assert(chain_info->u.pLayerInfo);
+    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
+    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
+    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+    uint32_t specified_version = (pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0);
+    uint32_t api_version = (specified_version < VK_API_VERSION_1_1) ? VK_API_VERSION_1_0 : VK_API_VERSION_1_1;
+
+
+    // Create temporary dispatch vector for pre-calls until instance is created
+    std::vector<ValidationObject*> local_object_dispatch;
+#if BUILD_OBJECT_TRACKER
+    auto object_tracker = new ObjectLifetimes;
+    local_object_dispatch.emplace_back(object_tracker);
+    object_tracker->container_type = LayerObjectTypeObjectTracker;
+    object_tracker->api_version = api_version;
+#elif BUILD_THREAD_SAFETY
+    auto thread_checker = new ThreadSafety;
+    local_object_dispatch.emplace_back(thread_checker);
+    thread_checker->container_type = LayerObjectTypeThreading;
+    thread_checker->api_version = api_version;
+#elif BUILD_PARAMETER_VALIDATION
+    auto parameter_validation = new StatelessValidation;
+    local_object_dispatch.emplace_back(parameter_validation);
+    parameter_validation->container_type = LayerObjectTypeParameterValidation;
+    parameter_validation->api_version = api_version;
+#elif BUILD_CORE_VALIDATION
+    auto core_checks = new CoreChecks;
+    local_object_dispatch.emplace_back(core_checks);
+    core_checks->container_type = LayerObjectTypeCoreValidation;
+    core_checks->api_version = api_version;
+#endif
+
+    // Init dispatch array and call registration functions
+    for (auto intercept : local_object_dispatch) {
+        intercept->PreCallValidateCreateInstance(pCreateInfo, pAllocator, pInstance);
+    }
+    for (auto intercept : local_object_dispatch) {
+        intercept->PreCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
+    }
+
+    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
+    if (result != VK_SUCCESS) return result;
+
+    auto framework = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
+
+    framework->object_dispatch = local_object_dispatch;
+    framework->container_type = LayerObjectTypeInstance;
+
+    framework->instance = *pInstance;
+    layer_init_instance_dispatch_table(*pInstance, &framework->instance_dispatch_table, fpGetInstanceProcAddr);
+    framework->report_data = debug_utils_create_instance(&framework->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
+                                                         pCreateInfo->ppEnabledExtensionNames);
+    framework->api_version = api_version;
+    framework->instance_extensions.InitFromInstanceCreateInfo(specified_version, pCreateInfo);
+
+    // Parse any pNext chains for validation features and flags
+    const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(pCreateInfo->pNext);
+    if (validation_flags_ext) {
+        SetDisabledFlags(framework, validation_flags_ext);
+    }
+    const auto *validation_features_ext = lvl_find_in_chain<VkValidationFeaturesEXT>(pCreateInfo->pNext);
+    if (validation_features_ext) {
+        SetValidationFeatures(framework, validation_features_ext);
+    }
+
+#if BUILD_OBJECT_TRACKER
+    layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_object_tracker");
+    object_tracker->report_data = framework->report_data;
+#elif BUILD_THREAD_SAFETY
+    layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "google_thread_checker");
+    thread_checker->report_data = framework->report_data;
+#elif BUILD_PARAMETER_VALIDATION
+    layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_parameter_validation");
+    parameter_validation->report_data = framework->report_data;
+#elif BUILD_CORE_VALIDATION
+    layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_core_validation");
+    core_checks->report_data = framework->report_data;
+    core_checks->instance_dispatch_table = framework->instance_dispatch_table;
+    core_checks->instance = *pInstance;
+    core_checks->enabled = framework->enabled;
+    core_checks->disabled = framework->disabled;
+    core_checks->instance_state = core_checks;
+#else
+    layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_unique_objects");
+#endif
+
+    for (auto intercept : framework->object_dispatch) {
+        intercept->PostCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance, result);
+    }
+
+    InstanceExtensionWhitelist(framework, pCreateInfo, *pInstance);
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(instance);
+    auto layer_data = GetLayerDataPtr(key, layer_data_map);
+    """ + precallvalidate_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PreCallValidateDestroyInstance(instance, pAllocator);
+    }
+    """ + precallrecord_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordDestroyInstance(instance, pAllocator);
+    }
+
+    layer_data->instance_dispatch_table.DestroyInstance(instance, pAllocator);
+
+    """ + postcallrecord_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordDestroyInstance(instance, pAllocator);
+    }
+    // Clean up logging callback, if any
+    while (layer_data->logging_messenger.size() > 0) {
+        VkDebugUtilsMessengerEXT messenger = layer_data->logging_messenger.back();
+        layer_destroy_messenger_callback(layer_data->report_data, messenger, pAllocator);
+        layer_data->logging_messenger.pop_back();
+    }
+    while (layer_data->logging_callback.size() > 0) {
+        VkDebugReportCallbackEXT callback = layer_data->logging_callback.back();
+        layer_destroy_report_callback(layer_data->report_data, callback, pAllocator);
+        layer_data->logging_callback.pop_back();
+    }
+
+    layer_debug_utils_destroy_instance(layer_data->report_data);
+
+    for (auto item = layer_data->object_dispatch.begin(); item != layer_data->object_dispatch.end(); item++) {
+        delete *item;
+    }
+    FreeLayerDataPtr(key, layer_data_map);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
+    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
+
+    auto instance_interceptor = GetLayerDataPtr(get_dispatch_key(gpu), layer_data_map);
+
+    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
+    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_interceptor->instance, "vkCreateDevice");
+    if (fpCreateDevice == NULL) {
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+
+    // Get physical device limits for device
+    VkPhysicalDeviceProperties device_properties = {};
+    instance_interceptor->instance_dispatch_table.GetPhysicalDeviceProperties(gpu, &device_properties);
+
+    // Setup the validation tables based on the application API version from the instance and the capabilities of the device driver
+    uint32_t effective_api_version = std::min(device_properties.apiVersion, instance_interceptor->api_version);
+
+    DeviceExtensions device_extensions = {};
+    device_extensions.InitFromDeviceCreateInfo(&instance_interceptor->instance_extensions, effective_api_version, pCreateInfo);
+    for (auto item : instance_interceptor->object_dispatch) {
+        item->device_extensions = device_extensions;
+    }
+
+    std::unique_ptr<safe_VkDeviceCreateInfo> modified_create_info(new safe_VkDeviceCreateInfo(pCreateInfo));
+
+    bool skip = false;
+    for (auto intercept : instance_interceptor->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : instance_interceptor->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, modified_create_info);
+    }
+
+    VkResult result = fpCreateDevice(gpu, reinterpret_cast<VkDeviceCreateInfo *>(modified_create_info.get()), pAllocator, pDevice);
+    if (result != VK_SUCCESS) {
+        return result;
+    }
+
+    auto device_interceptor = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
+    device_interceptor->container_type = LayerObjectTypeDevice;
+
+    // Save local info in device object
+    device_interceptor->phys_dev_properties.properties = device_properties;
+    device_interceptor->api_version = device_interceptor->device_extensions.InitFromDeviceCreateInfo(
+        &instance_interceptor->instance_extensions, effective_api_version, pCreateInfo);
+    device_interceptor->device_extensions = device_extensions;
+
+    layer_init_device_dispatch_table(*pDevice, &device_interceptor->device_dispatch_table, fpGetDeviceProcAddr);
+
+    device_interceptor->device = *pDevice;
+    device_interceptor->physical_device = gpu;
+    device_interceptor->instance = instance_interceptor->instance;
+    device_interceptor->report_data = layer_debug_utils_create_device(instance_interceptor->report_data, *pDevice);
+
+#if BUILD_OBJECT_TRACKER
+    // Create child layer objects for this key and add to dispatch vector
+    auto object_tracker = new ObjectLifetimes;
+    // TODO:  Initialize child objects with parent info thru constuctor taking a parent object
+    object_tracker->container_type = LayerObjectTypeObjectTracker;
+    object_tracker->physical_device = gpu;
+    object_tracker->instance = instance_interceptor->instance;
+    object_tracker->report_data = device_interceptor->report_data;
+    object_tracker->device_dispatch_table = device_interceptor->device_dispatch_table;
+    object_tracker->api_version = device_interceptor->api_version;
+    device_interceptor->object_dispatch.emplace_back(object_tracker);
+#elif BUILD_THREAD_SAFETY
+    auto thread_safety = new ThreadSafety;
+    // TODO:  Initialize child objects with parent info thru constuctor taking a parent object
+    thread_safety->container_type = LayerObjectTypeThreading;
+    thread_safety->physical_device = gpu;
+    thread_safety->instance = instance_interceptor->instance;
+    thread_safety->report_data = device_interceptor->report_data;
+    thread_safety->device_dispatch_table = device_interceptor->device_dispatch_table;
+    thread_safety->api_version = device_interceptor->api_version;
+    device_interceptor->object_dispatch.emplace_back(thread_safety);
+#elif BUILD_PARAMETER_VALIDATION
+    auto stateless_validation = new StatelessValidation;
+    // TODO:  Initialize child objects with parent info thru constuctor taking a parent object
+    stateless_validation->container_type = LayerObjectTypeParameterValidation;
+    stateless_validation->physical_device = gpu;
+    stateless_validation->instance = instance_interceptor->instance;
+    stateless_validation->report_data = device_interceptor->report_data;
+    stateless_validation->device_dispatch_table = device_interceptor->device_dispatch_table;
+    stateless_validation->api_version = device_interceptor->api_version;
+    device_interceptor->object_dispatch.emplace_back(stateless_validation);
+#elif BUILD_CORE_VALIDATION
+    auto core_checks = new CoreChecks;
+    // TODO:  Initialize child objects with parent info thru constuctor taking a parent object
+    core_checks->container_type = LayerObjectTypeCoreValidation;
+    core_checks->physical_device = gpu;
+    core_checks->instance = instance_interceptor->instance;
+    core_checks->report_data = device_interceptor->report_data;
+    core_checks->device_dispatch_table = device_interceptor->device_dispatch_table;
+    core_checks->instance_dispatch_table = instance_interceptor->instance_dispatch_table;
+    core_checks->api_version = device_interceptor->api_version;
+    core_checks->instance_extensions = instance_interceptor->instance_extensions;
+    core_checks->device_extensions = device_interceptor->device_extensions;
+    core_checks->instance_state = reinterpret_cast<CoreChecks *>(
+        core_checks->GetValidationObject(instance_interceptor->object_dispatch, LayerObjectTypeCoreValidation));
+    core_checks->device = *pDevice;
+    device_interceptor->object_dispatch.emplace_back(core_checks);
+#endif
+
+    for (auto intercept : instance_interceptor->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
+    }
+
+    DeviceExtensionWhitelist(device_interceptor, pCreateInfo, *pDevice);
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(device);
+    auto layer_data = GetLayerDataPtr(key, layer_data_map);
+    """ + precallvalidate_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PreCallValidateDestroyDevice(device, pAllocator);
+    }
+    """ + precallrecord_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordDestroyDevice(device, pAllocator);
+    }
+    layer_debug_utils_destroy_device(device);
+
+    layer_data->device_dispatch_table.DestroyDevice(device, pAllocator);
+
+    """ + postcallrecord_loop + """
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordDestroyDevice(device, pAllocator);
+    }
+
+    for (auto item = layer_data->object_dispatch.begin(); item != layer_data->object_dispatch.end(); item++) {
+        delete *item;
+    }
+    FreeLayerDataPtr(key, layer_data_map);
+}
+
+
+// Special-case APIs for which core_validation needs custom parameter lists and/or modifies parameters
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    createInfoCount,
+    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipeline*                                 pPipelines) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifdef BUILD_CORE_VALIDATION
+        create_graphics_pipeline_api_state cgpl_state{};
+#else
+        struct create_graphics_pipeline_api_state {
+            const VkGraphicsPipelineCreateInfo* pCreateInfos;
+        } cgpl_state;
+        cgpl_state.pCreateInfos = pCreateInfos;
+#endif
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, &cgpl_state);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, &cgpl_state);
+    }
+
+    VkResult result = DispatchCreateGraphicsPipelines(layer_data, device, pipelineCache, createInfoCount, cgpl_state.pCreateInfos, pAllocator, pPipelines);
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result, &cgpl_state);
+    }
+    return result;
+}
+
+// This API saves some core_validation pipeline state state on the stack for performance purposes
+VKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    createInfoCount,
+    const VkComputePipelineCreateInfo*          pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipeline*                                 pPipelines) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifndef BUILD_CORE_VALIDATION
+    struct PIPELINE_STATE {};
+#endif
+
+    std::vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, &pipe_state);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+    }
+    VkResult result = DispatchCreateComputePipelines(layer_data, device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result, &pipe_state);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateRayTracingPipelinesNV(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    createInfoCount,
+    const VkRayTracingPipelineCreateInfoNV*     pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipeline*                                 pPipelines) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifndef BUILD_CORE_VALIDATION
+    struct PIPELINE_STATE {};
+#endif
+
+    std::vector<std::unique_ptr<PIPELINE_STATE>> pipe_state;
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreateRayTracingPipelinesNV(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, &pipe_state);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+    }
+    VkResult result = DispatchCreateRayTracingPipelinesNV(layer_data, device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result, &pipe_state);
+    }
+    return result;
+}
+
+// This API needs the ability to modify a down-chain parameter
+VKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(
+    VkDevice                                    device,
+    const VkPipelineLayoutCreateInfo*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipelineLayout*                           pPipelineLayout) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifndef BUILD_CORE_VALIDATION
+    struct create_pipeline_layout_api_state {
+        VkPipelineLayoutCreateInfo modified_create_info;
+    };
+#endif
+    create_pipeline_layout_api_state cpl_state{};
+    cpl_state.modified_create_info = *pCreateInfo;
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, &cpl_state);
+    }
+    VkResult result = DispatchCreatePipelineLayout(layer_data, device, &cpl_state.modified_create_info, pAllocator, pPipelineLayout);
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, result);
+    }
+    return result;
+}
+
+// This API needs some local stack data for performance reasons and also may modify a parameter
+VKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(
+    VkDevice                                    device,
+    const VkShaderModuleCreateInfo*             pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkShaderModule*                             pShaderModule) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifndef BUILD_CORE_VALIDATION
+    struct create_shader_module_api_state {
+        VkShaderModuleCreateInfo instrumented_create_info;
+    };
+#endif
+    create_shader_module_api_state csm_state{};
+    csm_state.instrumented_create_info = *pCreateInfo;
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule, &csm_state);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule, &csm_state);
+    }
+    VkResult result = DispatchCreateShaderModule(layer_data, device, &csm_state.instrumented_create_info, pAllocator, pShaderModule);
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule, result, &csm_state);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(
+    VkDevice                                    device,
+    const VkDescriptorSetAllocateInfo*          pAllocateInfo,
+    VkDescriptorSet*                            pDescriptorSets) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+#ifdef BUILD_CORE_VALIDATION
+    cvdescriptorset::AllocateDescriptorSetsData ads_state(pAllocateInfo->descriptorSetCount);
+#else
+    struct ads_state {} ads_state;
+#endif
+
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        skip |= intercept->PreCallValidateAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets, &ads_state);
+        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PreCallRecordAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
+    }
+    VkResult result = DispatchAllocateDescriptorSets(layer_data, device, pAllocateInfo, pDescriptorSets);
+    for (auto intercept : layer_data->object_dispatch) {
+        auto lock = intercept->write_lock();
+        intercept->PostCallRecordAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets, result, &ads_state);
+    }
+    return result;
+}
+
+
+
+
+
+// ValidationCache APIs do not dispatch
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateValidationCacheEXT(
+    VkDevice                                    device,
+    const VkValidationCacheCreateInfoEXT*       pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkValidationCacheEXT*                       pValidationCache) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+
+    ValidationObject *validation_data = layer_data->GetValidationObject(layer_data->object_dispatch, LayerObjectTypeCoreValidation);
+    if (validation_data) {
+        auto lock = validation_data->write_lock();
+        result = validation_data->CoreLayerCreateValidationCacheEXT(device, pCreateInfo, pAllocator, pValidationCache);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyValidationCacheEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        validationCache,
+    const VkAllocationCallbacks*                pAllocator) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+    ValidationObject *validation_data = layer_data->GetValidationObject(layer_data->object_dispatch, LayerObjectTypeCoreValidation);
+    if (validation_data) {
+        auto lock = validation_data->write_lock();
+        validation_data->CoreLayerDestroyValidationCacheEXT(device, validationCache, pAllocator);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL MergeValidationCachesEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        dstCache,
+    uint32_t                                    srcCacheCount,
+    const VkValidationCacheEXT*                 pSrcCaches) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+
+    ValidationObject *validation_data = layer_data->GetValidationObject(layer_data->object_dispatch, LayerObjectTypeCoreValidation);
+    if (validation_data) {
+        auto lock = validation_data->write_lock();
+        result = validation_data->CoreLayerMergeValidationCachesEXT(device, dstCache, srcCacheCount, pSrcCaches);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetValidationCacheDataEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        validationCache,
+    size_t*                                     pDataSize,
+    void*                                       pData) {
+    auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+
+    ValidationObject *validation_data = layer_data->GetValidationObject(layer_data->object_dispatch, LayerObjectTypeCoreValidation);
+    if (validation_data) {
+        auto lock = validation_data->write_lock();
+        result = validation_data->CoreLayerGetValidationCacheDataEXT(device, validationCache, pDataSize, pData);
+    }
+    return result;
+
+}"""
+
+    inline_custom_validation_class_definitions = """
+        virtual VkResult CoreLayerCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache) { return VK_SUCCESS; };
+        virtual void CoreLayerDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator) {};
+        virtual VkResult CoreLayerMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches)  { return VK_SUCCESS; };
+        virtual VkResult CoreLayerGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData)  { return VK_SUCCESS; };
+
+        // Allow additional parameter for CreateGraphicsPipelines
+        virtual bool PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* cgpl_state) {
+            return PreCallValidateCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+        };
+        virtual void PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* cgpl_state) {
+            PreCallRecordCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+        };
+        virtual void PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result, void* cgpl_state) {
+            PostCallRecordCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result);
+        };
+
+        // Allow additional state parameter for CreateComputePipelines
+        virtual bool PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* pipe_state)  {
+            return PreCallValidateCreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+        };
+        virtual void PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result, void* pipe_state) {
+            PostCallRecordCreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result);
+        };
+
+        // Allow additional state parameter for CreateRayTracingPipelinesNV
+        virtual bool PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, void* pipe_state)  {
+            return PreCallValidateCreateRayTracingPipelinesNV(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
+        };
+        virtual void PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines, VkResult result, void* pipe_state) {
+            PostCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines, result);
+        };
+
+        // Allow modification of a down-chain parameter for CreatePipelineLayout
+        virtual void PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout, void *cpl_state) {
+            PreCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
+        };
+
+        // Enable the CreateShaderModule API to take an extra argument for state preservation and paramter modification
+        virtual bool PreCallValidateCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule, void* csm_state)  {
+            return PreCallValidateCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
+        };
+        virtual void PreCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule, void* csm_state) {
+            PreCallRecordCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
+        };
+        virtual void PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule, VkResult result, void* csm_state) {
+            PostCallRecordCreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule, result);
+        };
+
+        // Allow AllocateDescriptorSets to use some local stack storage for performance purposes
+        virtual bool PreCallValidateAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets, void* ads_state)  {
+            return PreCallValidateAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
+        };
+        virtual void PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets, VkResult result, void* ads_state)  {
+            PostCallRecordAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets, result);
+        };
+
+        // Modify a parameter to CreateDevice
+        virtual void PreCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice, std::unique_ptr<safe_VkDeviceCreateInfo> &modified_create_info) {
+            PreCallRecordCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
+        };
+"""
+
+    inline_custom_source_postamble = """
+// loader-layer interface v0, just wrappers since there is only a layer
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
+                                                                                      VkExtensionProperties *pProperties) {
+    return vulkan_layer_chassis::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
+                                                                                  VkLayerProperties *pProperties) {
+    return vulkan_layer_chassis::EnumerateInstanceLayerProperties(pCount, pProperties);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
+                                                                                VkLayerProperties *pProperties) {
+    // the layer command handles VK_NULL_HANDLE just fine internally
+    assert(physicalDevice == VK_NULL_HANDLE);
+    return vulkan_layer_chassis::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
+                                                                                    const char *pLayerName, uint32_t *pCount,
+                                                                                    VkExtensionProperties *pProperties) {
+    // the layer command handles VK_NULL_HANDLE just fine internally
+    assert(physicalDevice == VK_NULL_HANDLE);
+    return vulkan_layer_chassis::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
+    return vulkan_layer_chassis::GetDeviceProcAddr(dev, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
+    return vulkan_layer_chassis::GetInstanceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
+                                                                                           const char *funcName) {
+    return vulkan_layer_chassis::GetPhysicalDeviceProcAddr(instance, funcName);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
+    assert(pVersionStruct != NULL);
+    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
+
+    // Fill in the function pointers if our version is at least capable of having the structure contain them.
+    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
+        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
+        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
+    }
+
+    return VK_SUCCESS;
+}"""
+
+
+    def __init__(self,
+                 errFile = sys.stderr,
+                 warnFile = sys.stderr,
+                 diagFile = sys.stdout):
+        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+        # Internal state - accumulators for different inner block text
+        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+        self.intercepts = []
+        self.layer_factory = ''                     # String containing base layer factory class definition
+
+    # Check if the parameter passed in is a pointer to an array
+    def paramIsArray(self, param):
+        return param.attrib.get('len') is not None
+
+    # Check if the parameter passed in is a pointer
+    def paramIsPointer(self, param):
+        ispointer = False
+        for elem in param:
+            if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
+                ispointer = True
+        return ispointer
+
+    # Check if an object is a non-dispatchable handle
+    def isHandleTypeNonDispatchable(self, handletype):
+        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+        if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
+            return True
+        else:
+            return False
+
+    # Check if an object is a dispatchable handle
+    def isHandleTypeDispatchable(self, handletype):
+        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+        if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
+            return True
+        else:
+            return False
+    #
+    #
+    def beginFile(self, genOpts):
+        OutputGenerator.beginFile(self, genOpts)
+        # Output Copyright
+        write(self.inline_copyright_message, file=self.outFile)
+        # Multiple inclusion protection
+        self.header = False
+        if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
+            self.header = True
+            write('#pragma once', file=self.outFile)
+            self.newline()
+        if self.header:
+            write(self.inline_custom_header_preamble, file=self.outFile)
+        else:
+            write(self.inline_custom_source_preamble, file=self.outFile)
+        self.layer_factory += self.inline_custom_header_class_definition
+    #
+    #
+    def endFile(self):
+        # Finish C++ namespace and multiple inclusion protection
+        self.newline()
+        if not self.header:
+            # Record intercepted procedures
+            write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
+            write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+            write('\n'.join(self.intercepts), file=self.outFile)
+            write('};\n', file=self.outFile)
+            self.newline()
+            write('} // namespace vulkan_layer_chassis', file=self.outFile)
+        if self.header:
+            self.newline()
+            # Output Layer Factory Class Definitions
+            self.layer_factory += self.inline_custom_validation_class_definitions
+            self.layer_factory += '};\n\n'
+            self.layer_factory += 'extern std::unordered_map<void*, ValidationObject*> layer_data_map;'
+            write(self.layer_factory, file=self.outFile)
+        else:
+            write(self.inline_custom_source_postamble, file=self.outFile)
+        # Finish processing in superclass
+        OutputGenerator.endFile(self)
+
+    def beginFeature(self, interface, emit):
+        # Start processing in superclass
+        OutputGenerator.beginFeature(self, interface, emit)
+        # Get feature extra protect
+        self.featureExtraProtect = GetFeatureProtect(interface)
+        # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this
+        # feature. They're only printed in endFeature().
+        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+
+    def endFeature(self):
+        # Actually write the interface to the output file.
+        if (self.emit):
+            self.newline()
+            # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
+            # or move it below the 'for section...' loop.
+            if (self.featureExtraProtect != None):
+                write('#ifdef', self.featureExtraProtect, file=self.outFile)
+            for section in self.TYPE_SECTIONS:
+                contents = self.sections[section]
+                if contents:
+                    write('\n'.join(contents), file=self.outFile)
+                    self.newline()
+            if (self.sections['command']):
+                write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
+                self.newline()
+            if (self.featureExtraProtect != None):
+                write('#endif //', self.featureExtraProtect, file=self.outFile)
+        # Finish processing in superclass
+        OutputGenerator.endFeature(self)
+    #
+    # Append a definition to the specified section
+    def appendSection(self, section, text):
+        self.sections[section].append(text)
+    #
+    # Type generation
+    def genType(self, typeinfo, name, alias):
+        pass
+    #
+    # Struct (e.g. C "struct" type) generation. This is a special case of the <type> tag where the contents are
+    # interpreted as a set of <member> tags instead of freeform C type declarations. The <member> tags are just like <param>
+    # tags - they are a declaration of a struct or union member. Only simple member declarations are supported (no nested
+    # structs etc.)
+    def genStruct(self, typeinfo, typeName):
+        OutputGenerator.genStruct(self, typeinfo, typeName)
+        body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
+        # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
+        for member in typeinfo.elem.findall('.//member'):
+            body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
+            body += ';\n'
+        body += '} ' + typeName + ';\n'
+        self.appendSection('struct', body)
+    #
+    # Group (e.g. C "enum" type) generation. These are concatenated together with other types.
+    def genGroup(self, groupinfo, groupName, alias):
+        pass
+    # Enumerant generation
+    # <enum> tags may specify their values in several ways, but are usually just integers.
+    def genEnum(self, enuminfo, name, alias):
+        pass
+    #
+    # Customize Cdecl for layer factory base class
+    def BaseClassCdecl(self, elem, name):
+        raw = self.makeCDecls(elem)[1]
+
+        # Toss everything before the undecorated name
+        prototype = raw.split("VKAPI_PTR *PFN_vk")[1]
+        prototype = prototype.replace(")", "", 1)
+        prototype = prototype.replace(";", " {};")
+
+        # Build up pre/post call virtual function declarations
+        pre_call_validate = 'virtual bool PreCallValidate' + prototype
+        pre_call_validate = pre_call_validate.replace("{}", " { return false; }")
+        pre_call_record = 'virtual void PreCallRecord' + prototype
+        post_call_record = 'virtual void PostCallRecord' + prototype
+        resulttype = elem.find('proto/type')
+        if resulttype.text == 'VkResult':
+            post_call_record = post_call_record.replace(')', ', VkResult result)')
+        return '        %s\n        %s\n        %s\n' % (pre_call_validate, pre_call_record, post_call_record)
+    #
+    # Command generation
+    def genCmd(self, cmdinfo, name, alias):
+        ignore_functions = [
+        'vkEnumerateInstanceVersion',
+        ]
+
+        if name in ignore_functions:
+            return
+
+        if self.header: # In the header declare all intercepts
+            self.appendSection('command', '')
+            self.appendSection('command', self.makeCDecls(cmdinfo.elem)[0])
+            if (self.featureExtraProtect != None):
+                self.layer_factory += '#ifdef %s\n' % self.featureExtraProtect
+            # Update base class with virtual function declarations
+            if 'ValidationCache' not in name:
+                self.layer_factory += self.BaseClassCdecl(cmdinfo.elem, name)
+            if (self.featureExtraProtect != None):
+                self.layer_factory += '#endif\n'
+            return
+
+        if name in self.manual_functions:
+            if 'ValidationCache' not in name:
+                self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
+            else:
+                self.intercepts += [ '#ifdef BUILD_CORE_VALIDATION' ]
+                self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
+                self.intercepts += [ '#endif' ]
+            return
+        # Record that the function will be intercepted
+        if (self.featureExtraProtect != None):
+            self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
+        self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
+        if (self.featureExtraProtect != None):
+            self.intercepts += [ '#endif' ]
+        OutputGenerator.genCmd(self, cmdinfo, name, alias)
+        #
+        decls = self.makeCDecls(cmdinfo.elem)
+        self.appendSection('command', '')
+        self.appendSection('command', '%s {' % decls[0][:-1])
+        # Setup common to call wrappers. First parameter is always dispatchable
+        dispatchable_type = cmdinfo.elem.find('param/type').text
+        dispatchable_name = cmdinfo.elem.find('param/name').text
+        # Default to device
+        device_or_instance = 'device'
+        dispatch_table_name = 'VkLayerDispatchTable'
+        # Set to instance as necessary
+        if dispatchable_type in ["VkPhysicalDevice", "VkInstance"] or name == 'vkCreateInstance':
+            device_or_instance = 'instance'
+            dispatch_table_name = 'VkLayerInstanceDispatchTable'
+        self.appendSection('command', '    auto layer_data = GetLayerDataPtr(get_dispatch_key(%s), layer_data_map);' % (dispatchable_name))
+        api_function_name = cmdinfo.elem.attrib.get('name')
+        params = cmdinfo.elem.findall('param/name')
+        paramstext = ', '.join([str(param.text) for param in params])
+        API = api_function_name.replace('vk','Dispatch') + '(layer_data, '
+
+        # Declare result variable, if any.
+        return_map = {
+            'PFN_vkVoidFunction': 'return nullptr;',
+            'VkBool32': 'return VK_FALSE;',
+            'VkDeviceAddress': 'return 0;',
+            'VkResult': 'return VK_ERROR_VALIDATION_FAILED_EXT;',
+            'void': 'return;',
+            'uint32_t': 'return 0;'
+            }
+        resulttype = cmdinfo.elem.find('proto/type')
+        assignresult = ''
+        if (resulttype.text != 'void'):
+            assignresult = resulttype.text + ' result = '
+
+        # Set up skip and locking
+        self.appendSection('command', '    bool skip = false;')
+
+        # Generate pre-call validation source code
+        self.appendSection('command', '    %s' % self.precallvalidate_loop)
+        self.appendSection('command', '        auto lock = intercept->write_lock();')
+        self.appendSection('command', '        skip |= intercept->PreCallValidate%s(%s);' % (api_function_name[2:], paramstext))
+        self.appendSection('command', '        if (skip) %s' % return_map[resulttype.text])
+        self.appendSection('command', '    }')
+
+        # Generate pre-call state recording source code
+        self.appendSection('command', '    %s' % self.precallrecord_loop)
+        self.appendSection('command', '        auto lock = intercept->write_lock();')
+        self.appendSection('command', '        intercept->PreCallRecord%s(%s);' % (api_function_name[2:], paramstext))
+        self.appendSection('command', '    }')
+
+        # Insert pre-dispatch debug utils function call
+        if name in self.pre_dispatch_debug_utils_functions:
+            self.appendSection('command', '    %s' % self.pre_dispatch_debug_utils_functions[name])
+
+        # Output dispatch (down-chain) function call
+        self.appendSection('command', '    ' + assignresult + API + paramstext + ');')
+
+        # Insert post-dispatch debug utils function call
+        if name in self.post_dispatch_debug_utils_functions:
+            self.appendSection('command', '    %s' % self.post_dispatch_debug_utils_functions[name])
+
+        # Generate post-call object processing source code
+        self.appendSection('command', '    %s' % self.postcallrecord_loop)
+        returnparam = ''
+        if (resulttype.text == 'VkResult'):
+            returnparam = ', result'
+        self.appendSection('command', '        auto lock = intercept->write_lock();')
+        self.appendSection('command', '        intercept->PostCallRecord%s(%s%s);' % (api_function_name[2:], paramstext, returnparam))
+        self.appendSection('command', '    }')
+        # Return result variable, if any.
+        if (resulttype.text != 'void'):
+            self.appendSection('command', '    return result;')
+        self.appendSection('command', '}')
+    #
+    # Override makeProtoName to drop the "vk" prefix
+    def makeProtoName(self, name, tail):
+        return self.genOpts.apientry + name[2:] + tail
diff --git a/scripts/layer_dispatch_table_generator.py b/scripts/layer_dispatch_table_generator.py
new file mode 100644
index 0000000..d5406f1
--- /dev/null
+++ b/scripts/layer_dispatch_table_generator.py
@@ -0,0 +1,368 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2015-2017 The Khronos Group Inc.
+# Copyright (c) 2015-2017 Valve Corporation
+# Copyright (c) 2015-2017 LunarG, Inc.
+# Copyright (c) 2015-2017 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Mark Young <marky@lunarg.com>
+# Author: Mark Lobodzinski <mark@lunarg.com>
+
+import os,re,sys
+import xml.etree.ElementTree as etree
+from generator import *
+from collections import namedtuple
+from common_codegen import *
+
+ADD_INST_CMDS = ['vkCreateInstance',
+                 'vkEnumerateInstanceExtensionProperties',
+                 'vkEnumerateInstanceLayerProperties',
+                 'vkEnumerateInstanceVersion']
+
+#
+# LayerDispatchTableGeneratorOptions - subclass of GeneratorOptions.
+class LayerDispatchTableGeneratorOptions(GeneratorOptions):
+    def __init__(self,
+                 filename = None,
+                 directory = '.',
+                 apiname = None,
+                 profile = None,
+                 versions = '.*',
+                 emitversions = '.*',
+                 defaultExtensions = None,
+                 addExtensions = None,
+                 removeExtensions = None,
+                 emitExtensions = None,
+                 sortProcedure = regSortFeatures,
+                 prefixText = "",
+                 genFuncPointers = True,
+                 protectFile = True,
+                 protectFeature = True,
+                 apicall = '',
+                 apientry = '',
+                 apientryp = '',
+                 indentFuncProto = True,
+                 indentFuncPointer = False,
+                 alignFuncParam = 0,
+                 expandEnumerants = True):
+        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
+                                  versions, emitversions, defaultExtensions,
+                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        self.prefixText      = prefixText
+        self.prefixText      = None
+        self.apicall         = apicall
+        self.apientry        = apientry
+        self.apientryp       = apientryp
+        self.alignFuncParam  = alignFuncParam
+        self.expandEnumerants = expandEnumerants
+
+#
+# LayerDispatchTableOutputGenerator - subclass of OutputGenerator.
+# Generates dispatch table helper header files for LVL
+class LayerDispatchTableOutputGenerator(OutputGenerator):
+    """Generate dispatch tables header based on XML element attributes"""
+    def __init__(self,
+                 errFile = sys.stderr,
+                 warnFile = sys.stderr,
+                 diagFile = sys.stdout):
+        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+
+        # Internal state - accumulators for different inner block text
+        self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
+        self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
+        self.core_commands = []               # List of CommandData records for core Vulkan commands
+        self.ext_commands = []                # List of CommandData records for extension Vulkan commands
+        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
+        self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
+
+    #
+    # Called once at the beginning of each run
+    def beginFile(self, genOpts):
+        OutputGenerator.beginFile(self, genOpts)
+
+        # User-supplied prefix text, if any (list of strings)
+        if (genOpts.prefixText):
+            for s in genOpts.prefixText:
+                write(s, file=self.outFile)
+
+        # File Comment
+        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
+        file_comment += '// See layer_dispatch_table_generator.py for modifications\n'
+        write(file_comment, file=self.outFile)
+
+        # Copyright Notice
+        copyright =  '/*\n'
+        copyright += ' * Copyright (c) 2015-2018 The Khronos Group Inc.\n'
+        copyright += ' * Copyright (c) 2015-2018 Valve Corporation\n'
+        copyright += ' * Copyright (c) 2015-2018 LunarG, Inc.\n'
+        copyright += ' *\n'
+        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
+        copyright += ' * you may not use this file except in compliance with the License.\n'
+        copyright += ' * You may obtain a copy of the License at\n'
+        copyright += ' *\n'
+        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
+        copyright += ' *\n'
+        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
+        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
+        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
+        copyright += ' * See the License for the specific language governing permissions and\n'
+        copyright += ' * limitations under the License.\n'
+        copyright += ' *\n'
+        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
+        copyright += ' * Author: Mark Young <marky@lunarg.com>\n'
+        copyright += ' */\n'
+
+        preamble = ''
+        if self.genOpts.filename == 'vk_layer_dispatch_table.h':
+            preamble += '#pragma once\n'
+            preamble += '\n'
+            preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
+
+        write(copyright, file=self.outFile)
+        write(preamble, file=self.outFile)
+
+    #
+    # Write generate and write dispatch tables to output file
+    def endFile(self):
+        file_data = ''
+        if self.genOpts.filename == 'vk_layer_dispatch_table.h':
+            file_data += self.OutputLayerInstanceDispatchTable()
+            file_data += self.OutputLayerDeviceDispatchTable()
+
+        write(file_data, file=self.outFile);
+
+        # Finish processing in superclass
+        OutputGenerator.endFile(self)
+
+    def beginFeature(self, interface, emit):
+        # Start processing in superclass
+        OutputGenerator.beginFeature(self, interface, emit)
+        self.featureExtraProtect = GetFeatureProtect(interface)
+
+        enums = interface[0].findall('enum')
+        self.currentExtension = ''
+
+        self.type = interface.get('type')
+        self.num_commands = 0
+        name = interface.get('name')
+        self.currentExtension = name
+
+    #
+    # Process commands, adding to appropriate dispatch tables
+    def genCmd(self, cmdinfo, name, alias):
+        OutputGenerator.genCmd(self, cmdinfo, name, alias)
+
+        # Get first param type
+        params = cmdinfo.elem.findall('param')
+        info = self.getTypeNameTuple(params[0])
+
+        self.num_commands += 1
+
+        if 'android' not in name:
+            self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
+
+    def endFeature(self):
+        # Finish processing in superclass
+        OutputGenerator.endFeature(self)
+
+    #
+    # Retrieve the value of the len tag
+    def getLen(self, param):
+        result = None
+        len = param.attrib.get('len')
+        if len and len != 'null-terminated':
+            # For string arrays, 'len' can look like 'count,null-terminated',
+            # indicating that we have a null terminated array of strings.  We
+            # strip the null-terminated from the 'len' field and only return
+            # the parameter specifying the string count
+            if 'null-terminated' in len:
+                result = len.split(',')[0]
+            else:
+                result = len
+            result = str(result).replace('::', '->')
+        return result
+
+    #
+    # Determine if this API should be ignored or added to the instance or device dispatch table
+    def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
+        handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
+
+        return_type =  cmdinfo.elem.find('proto/type')
+        if (return_type is not None and return_type.text == 'void'):
+           return_type = None
+
+        cmd_params = []
+
+        # Generate a list of commands for use in printing the necessary
+        # core instance terminator prototypes
+        params = cmdinfo.elem.findall('param')
+        lens = set()
+        for param in params:
+            len = self.getLen(param)
+            if len:
+                lens.add(len)
+        paramsInfo = []
+        for param in params:
+            paramInfo = self.getTypeNameTuple(param)
+            param_type = paramInfo[0]
+            param_name = paramInfo[1]
+            param_cdecl = self.makeCParamDecl(param, 0)
+            cmd_params.append(self.CommandParam(type=param_type, name=param_name,
+                                                cdecl=param_cdecl))
+
+        if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
+            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
+            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
+            if 'VK_VERSION_' in extension_name:
+                self.core_commands.append(
+                    self.CommandData(name=name, ext_name=extension_name,
+                                     ext_type='device',
+                                     protect=self.featureExtraProtect,
+                                     return_type = return_type,
+                                     handle_type = handle_type,
+                                     params = cmd_params,
+                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
+            else:
+                self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
+                self.ext_commands.append(
+                    self.CommandData(name=name, ext_name=extension_name,
+                                     ext_type=extension_type,
+                                     protect=self.featureExtraProtect,
+                                     return_type = return_type,
+                                     handle_type = handle_type,
+                                     params = cmd_params,
+                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
+        else:
+            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
+            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
+            if 'VK_VERSION_' in extension_name:
+                self.core_commands.append(
+                    self.CommandData(name=name, ext_name=extension_name,
+                                     ext_type='instance',
+                                     protect=self.featureExtraProtect,
+                                     return_type = return_type,
+                                     handle_type = handle_type,
+                                     params = cmd_params,
+                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
+
+            else:
+                self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
+                self.ext_commands.append(
+                    self.CommandData(name=name, ext_name=extension_name,
+                                     ext_type=extension_type,
+                                     protect=self.featureExtraProtect,
+                                     return_type = return_type,
+                                     handle_type = handle_type,
+                                     params = cmd_params,
+                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
+
+    #
+    # Retrieve the type and name for a parameter
+    def getTypeNameTuple(self, param):
+        type = ''
+        name = ''
+        for elem in param:
+            if elem.tag == 'type':
+                type = noneStr(elem.text)
+            elif elem.tag == 'name':
+                name = noneStr(elem.text)
+        return (type, name)
+
+    #
+    # Create a layer instance dispatch table from the appropriate list and return it as a string
+    def OutputLayerInstanceDispatchTable(self):
+        commands = []
+        table = ''
+        cur_extension_name = ''
+
+        table += '// Instance function pointer dispatch table\n'
+        table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
+
+        # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
+        # ever show up in the XML or header, so we have to manually add it.
+        table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
+        table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
+
+        for x in range(0, 2):
+            if x == 0:
+                commands = self.core_commands
+            else:
+                commands = self.ext_commands
+
+            for cur_cmd in commands:
+                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                if is_inst_handle_type:
+
+                    if cur_cmd.ext_name != cur_extension_name:
+                        if 'VK_VERSION_' in cur_cmd.ext_name:
+                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
+                        else:
+                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
+                        cur_extension_name = cur_cmd.ext_name
+
+                    # Remove 'vk' from proto name
+                    base_name = cur_cmd.name[2:]
+
+                    if cur_cmd.protect is not None:
+                        table += '#ifdef %s\n' % cur_cmd.protect
+
+                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
+
+                    if cur_cmd.protect is not None:
+                        table += '#endif // %s\n' % cur_cmd.protect
+
+        table += '} VkLayerInstanceDispatchTable;\n\n'
+        return table
+
+    #
+    # Create a layer device dispatch table from the appropriate list and return it as a string
+    def OutputLayerDeviceDispatchTable(self):
+        commands = []
+        table = ''
+        cur_extension_name = ''
+
+        table += '// Device function pointer dispatch table\n'
+        table += 'typedef struct VkLayerDispatchTable_ {\n'
+
+        for x in range(0, 2):
+            if x == 0:
+                commands = self.core_commands
+            else:
+                commands = self.ext_commands
+
+            for cur_cmd in commands:
+                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                if not is_inst_handle_type:
+
+                    if cur_cmd.ext_name != cur_extension_name:
+                        if 'VK_VERSION_' in cur_cmd.ext_name:
+                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
+                        else:
+                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
+                        cur_extension_name = cur_cmd.ext_name
+
+                    # Remove 'vk' from proto name
+                    base_name = cur_cmd.name[2:]
+
+                    if cur_cmd.protect is not None:
+                        table += '#ifdef %s\n' % cur_cmd.protect
+
+                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
+
+                    if cur_cmd.protect is not None:
+                        table += '#endif // %s\n' % cur_cmd.protect
+
+        table += '} VkLayerDispatchTable;\n\n'
+        return table
diff --git a/scripts/loader_extension_generator.py b/scripts/loader_extension_generator.py
deleted file mode 100644
index e198749..0000000
--- a/scripts/loader_extension_generator.py
+++ /dev/null
@@ -1,1493 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2015-2017 The Khronos Group Inc.
-# Copyright (c) 2015-2017 Valve Corporation
-# Copyright (c) 2015-2017 LunarG, Inc.
-# Copyright (c) 2015-2017 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Author: Mark Young <marky@lunarg.com>
-# Author: Mark Lobodzinski <mark@lunarg.com>
-
-import os,re,sys
-import xml.etree.ElementTree as etree
-from generator import *
-from collections import namedtuple
-from common_codegen import *
-
-
-WSI_EXT_NAMES = ['VK_KHR_surface',
-                 'VK_KHR_display',
-                 'VK_KHR_xlib_surface',
-                 'VK_KHR_xcb_surface',
-                 'VK_KHR_wayland_surface',
-                 'VK_KHR_win32_surface',
-                 'VK_KHR_android_surface',
-                 'VK_MVK_macos_surface',
-                 'VK_MVK_ios_surface',
-                 'VK_KHR_swapchain',
-                 'VK_KHR_display_swapchain']
-
-ADD_INST_CMDS = ['vkCreateInstance',
-                 'vkEnumerateInstanceExtensionProperties',
-                 'vkEnumerateInstanceLayerProperties',
-                 'vkEnumerateInstanceVersion']
-
-AVOID_EXT_NAMES = ['VK_EXT_debug_report']
-
-AVOID_CMD_NAMES = ['vkCreateDebugUtilsMessengerEXT',
-                   'vkDestroyDebugUtilsMessengerEXT',
-                   'vkSubmitDebugUtilsMessageEXT']
-
-DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr',
-                         'vkCreateSwapchainKHR',
-                         'vkCreateSharedSwapchainsKHR',
-                         'vkGetDeviceGroupSurfacePresentModesKHR',
-                         'vkDebugMarkerSetObjectTagEXT',
-                         'vkDebugMarkerSetObjectNameEXT',
-                         'vkSetDebugUtilsObjectNameEXT',
-                         'vkSetDebugUtilsObjectTagEXT']
-                         
-ALIASED_CMDS = {
-    'vkEnumeratePhysicalDeviceGroupsKHR':                   'vkEnumeratePhysicalDeviceGroups',
-    'vkGetPhysicalDeviceFeatures2KHR':                      'vkGetPhysicalDeviceFeatures2',
-    'vkGetPhysicalDeviceProperties2KHR':                    'vkGetPhysicalDeviceProperties2',
-    'vkGetPhysicalDeviceFormatProperties2KHR':              'vkGetPhysicalDeviceFormatProperties2',
-    'vkGetPhysicalDeviceImageFormatProperties2KHR':         'vkGetPhysicalDeviceImageFormatProperties2',
-    'vkGetPhysicalDeviceQueueFamilyProperties2KHR':         'vkGetPhysicalDeviceQueueFamilyProperties2',
-    'vkGetPhysicalDeviceMemoryProperties2KHR':              'vkGetPhysicalDeviceMemoryProperties2',
-    'vkGetPhysicalDeviceSparseImageFormatProperties2KHR':   'vkGetPhysicalDeviceSparseImageFormatProperties2',
-    'vkGetPhysicalDeviceExternalBufferPropertiesKHR':       'vkGetPhysicalDeviceExternalBufferProperties',
-    'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR':    'vkGetPhysicalDeviceExternalSemaphoreProperties',
-    'vkGetPhysicalDeviceExternalFencePropertiesKHR':        'vkGetPhysicalDeviceExternalFenceProperties',
-}
-
-PRE_INSTANCE_FUNCTIONS = ['vkEnumerateInstanceExtensionProperties',
-                          'vkEnumerateInstanceLayerProperties',
-                          'vkEnumerateInstanceVersion']
-
-#
-# LoaderExtensionGeneratorOptions - subclass of GeneratorOptions.
-class LoaderExtensionGeneratorOptions(GeneratorOptions):
-    def __init__(self,
-                 filename = None,
-                 directory = '.',
-                 apiname = None,
-                 profile = None,
-                 versions = '.*',
-                 emitversions = '.*',
-                 defaultExtensions = None,
-                 addExtensions = None,
-                 removeExtensions = None,
-                 emitExtensions = None,
-                 sortProcedure = regSortFeatures,
-                 prefixText = "",
-                 genFuncPointers = True,
-                 protectFile = True,
-                 protectFeature = True,
-                 apicall = '',
-                 apientry = '',
-                 apientryp = '',
-                 indentFuncProto = True,
-                 indentFuncPointer = False,
-                 alignFuncParam = 0,
-                 expandEnumerants = True):
-        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
-        self.prefixText      = prefixText
-        self.prefixText      = None
-        self.apicall         = apicall
-        self.apientry        = apientry
-        self.apientryp       = apientryp
-        self.alignFuncParam  = alignFuncParam
-        self.expandEnumerants = expandEnumerants
-
-#
-# LoaderExtensionOutputGenerator - subclass of OutputGenerator.
-# Generates dispatch table helper header files for LVL
-class LoaderExtensionOutputGenerator(OutputGenerator):
-    """Generate dispatch table helper header based on XML element attributes"""
-    def __init__(self,
-                 errFile = sys.stderr,
-                 warnFile = sys.stderr,
-                 diagFile = sys.stdout):
-        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
-
-        # Internal state - accumulators for different inner block text
-        self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
-        self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
-        self.core_commands = []               # List of CommandData records for core Vulkan commands
-        self.ext_commands = []                # List of CommandData records for extension Vulkan commands
-        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
-        self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
-        self.instanceExtensions = []
-        self.ExtensionData = namedtuple('ExtensionData', ['name', 'type', 'protect', 'define', 'num_commands'])
-
-    #
-    # Called once at the beginning of each run
-    def beginFile(self, genOpts):
-        OutputGenerator.beginFile(self, genOpts)
-
-        # User-supplied prefix text, if any (list of strings)
-        if (genOpts.prefixText):
-            for s in genOpts.prefixText:
-                write(s, file=self.outFile)
-
-        # File Comment
-        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
-        file_comment += '// See loader_extension_generator.py for modifications\n'
-        write(file_comment, file=self.outFile)
-
-        # Copyright Notice
-        copyright =  '/*\n'
-        copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
-        copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
-        copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
-        copyright += ' *\n'
-        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
-        copyright += ' * you may not use this file except in compliance with the License.\n'
-        copyright += ' * You may obtain a copy of the License at\n'
-        copyright += ' *\n'
-        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
-        copyright += ' *\n'
-        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
-        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
-        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
-        copyright += ' * See the License for the specific language governing permissions and\n'
-        copyright += ' * limitations under the License.\n'
-        copyright += ' *\n'
-        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
-        copyright += ' * Author: Mark Young <marky@lunarg.com>\n'
-        copyright += ' */\n'
-
-        preamble = ''
-
-        if self.genOpts.filename == 'vk_loader_extensions.h':
-            preamble += '#pragma once\n'
-
-        elif self.genOpts.filename == 'vk_loader_extensions.c':
-            preamble += '#define _GNU_SOURCE\n'
-            preamble += '#include <stdio.h>\n'
-            preamble += '#include <stdlib.h>\n'
-            preamble += '#include <string.h>\n'
-            preamble += '#include "vk_loader_platform.h"\n'
-            preamble += '#include "loader.h"\n'
-            preamble += '#include "vk_loader_extensions.h"\n'
-            preamble += '#include <vulkan/vk_icd.h>\n'
-            preamble += '#include "wsi.h"\n'
-            preamble += '#include "debug_utils.h"\n'
-            preamble += '#include "extension_manual.h"\n'
-
-        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
-            preamble += '#pragma once\n'
-            preamble += '\n'
-            preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
-
-        write(copyright, file=self.outFile)
-        write(preamble, file=self.outFile)
-
-    #
-    # Write generate and write dispatch tables to output file
-    def endFile(self):
-        file_data = ''
-
-        if self.genOpts.filename == 'vk_loader_extensions.h':
-            file_data += self.OutputPrototypesInHeader()
-            file_data += self.OutputLoaderTerminators()
-            file_data += self.OutputIcdDispatchTable()
-            file_data += self.OutputIcdExtensionEnableUnion()
-
-        elif self.genOpts.filename == 'vk_loader_extensions.c':
-            file_data += self.OutputUtilitiesInSource()
-            file_data += self.OutputIcdDispatchTableInit()
-            file_data += self.OutputLoaderDispatchTables()
-            file_data += self.OutputLoaderLookupFunc()
-            file_data += self.CreateTrampTermFuncs()
-            file_data += self.InstExtensionGPA()
-            file_data += self.InstantExtensionCreate()
-            file_data += self.DeviceExtensionGetTerminator()
-            file_data += self.InitInstLoaderExtensionDispatchTable()
-            file_data += self.OutputInstantExtensionWhitelistArray()
-
-        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
-            file_data += self.OutputLayerInstanceDispatchTable()
-            file_data += self.OutputLayerDeviceDispatchTable()
-
-        write(file_data, file=self.outFile);
-
-        # Finish processing in superclass
-        OutputGenerator.endFile(self)
-
-    def beginFeature(self, interface, emit):
-        # Start processing in superclass
-        OutputGenerator.beginFeature(self, interface, emit)
-        self.featureExtraProtect = GetFeatureProtect(interface)
-
-        enums = interface[0].findall('enum')
-        self.currentExtension = ''
-        self.name_definition = ''
-
-        for item in enums:
-            name_definition = item.get('name')
-            if 'EXTENSION_NAME' in name_definition:
-                self.name_definition = name_definition
-
-        self.type = interface.get('type')
-        self.num_commands = 0
-        name = interface.get('name')
-        self.currentExtension = name 
-
-    #
-    # Process commands, adding to appropriate dispatch tables
-    def genCmd(self, cmdinfo, name, alias):
-        OutputGenerator.genCmd(self, cmdinfo, name, alias)
-
-        # Get first param type
-        params = cmdinfo.elem.findall('param')
-        info = self.getTypeNameTuple(params[0])
-
-        self.num_commands += 1
-
-        if 'android' not in name:
-            self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
-
-    def endFeature(self):
-
-        if 'android' not in self.currentExtension:
-            self.instanceExtensions.append(self.ExtensionData(name=self.currentExtension,
-                                                              type=self.type,
-                                                              protect=self.featureExtraProtect,
-                                                              define=self.name_definition,
-                                                              num_commands=self.num_commands))
-
-        # Finish processing in superclass
-        OutputGenerator.endFeature(self)
-
-    #
-    # Retrieve the value of the len tag
-    def getLen(self, param):
-        result = None
-        len = param.attrib.get('len')
-        if len and len != 'null-terminated':
-            # For string arrays, 'len' can look like 'count,null-terminated',
-            # indicating that we have a null terminated array of strings.  We
-            # strip the null-terminated from the 'len' field and only return
-            # the parameter specifying the string count
-            if 'null-terminated' in len:
-                result = len.split(',')[0]
-            else:
-                result = len
-            result = str(result).replace('::', '->')
-        return result
-
-    #
-    # Determine if this API should be ignored or added to the instance or device dispatch table
-    def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
-        handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
-
-        return_type =  cmdinfo.elem.find('proto/type')
-        if (return_type != None and return_type.text == 'void'):
-           return_type = None
-
-        cmd_params = []
-
-        # Generate a list of commands for use in printing the necessary
-        # core instance terminator prototypes
-        params = cmdinfo.elem.findall('param')
-        lens = set()
-        for param in params:
-            len = self.getLen(param)
-            if len:
-                lens.add(len)
-        paramsInfo = []
-        for param in params:
-            paramInfo = self.getTypeNameTuple(param)
-            param_type = paramInfo[0]
-            param_name = paramInfo[1]
-            param_cdecl = self.makeCParamDecl(param, 0)
-            cmd_params.append(self.CommandParam(type=param_type, name=param_name,
-                                                cdecl=param_cdecl))
-
-        if handle != None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
-            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
-            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
-            if 'VK_VERSION_' in extension_name:
-                self.core_commands.append(
-                    self.CommandData(name=name, ext_name=extension_name,
-                                     ext_type='device',
-                                     protect=self.featureExtraProtect,
-                                     return_type = return_type,
-                                     handle_type = handle_type,
-                                     params = cmd_params,
-                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
-            else:
-                self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
-                self.ext_commands.append(
-                    self.CommandData(name=name, ext_name=extension_name,
-                                     ext_type=extension_type,
-                                     protect=self.featureExtraProtect,
-                                     return_type = return_type,
-                                     handle_type = handle_type,
-                                     params = cmd_params,
-                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
-        else:
-            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
-            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
-            if 'VK_VERSION_' in extension_name:
-                self.core_commands.append(
-                    self.CommandData(name=name, ext_name=extension_name,
-                                     ext_type='instance',
-                                     protect=self.featureExtraProtect,
-                                     return_type = return_type,
-                                     handle_type = handle_type,
-                                     params = cmd_params,
-                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
-
-            else:
-                self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
-                self.ext_commands.append(
-                    self.CommandData(name=name, ext_name=extension_name,
-                                     ext_type=extension_type,
-                                     protect=self.featureExtraProtect,
-                                     return_type = return_type,
-                                     handle_type = handle_type,
-                                     params = cmd_params,
-                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
-
-    #
-    # Retrieve the type and name for a parameter
-    def getTypeNameTuple(self, param):
-        type = ''
-        name = ''
-        for elem in param:
-            if elem.tag == 'type':
-                type = noneStr(elem.text)
-            elif elem.tag == 'name':
-                name = noneStr(elem.text)
-        return (type, name)
-
-    def OutputPrototypesInHeader(self):
-        protos = ''
-        protos += '// Structures defined externally, but used here\n'
-        protos += 'struct loader_instance;\n'
-        protos += 'struct loader_device;\n'
-        protos += 'struct loader_icd_term;\n'
-        protos += 'struct loader_dev_dispatch_table;\n'
-        protos += '\n'
-        protos += '// Device extension error function\n'
-        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev);\n'
-        protos += '\n'
-        protos += '// Extension interception for vkGetInstanceProcAddr function, so we can return\n'
-        protos += '// the appropriate information for any instance extensions we know about.\n'
-        protos += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);\n'
-        protos += '\n'
-        protos += '// Extension interception for vkCreateInstance function, so we can properly\n'
-        protos += '// detect and enable any instance extension information for extensions we know\n'
-        protos += '// about.\n'
-        protos += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);\n'
-        protos += '\n'
-        protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n'
-        protos += '// an appropriate terminator if this is one of those few device commands requiring\n'
-        protos += '// a terminator.\n'
-        protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName);\n'
-        protos += '\n'
-        protos += '// Dispatch table properly filled in with appropriate terminators for the\n'
-        protos += '// supported extensions.\n'
-        protos += 'extern const VkLayerInstanceDispatchTable instance_disp;\n'
-        protos += '\n'
-        protos += '// Array of extension strings for instance extensions we support.\n'
-        protos += 'extern const char *const LOADER_INSTANCE_EXTENSIONS[];\n'
-        protos += '\n'
-        protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
-        protos += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa);\n'
-        protos += '\n'
-        protos += '// Init Device function pointer dispatch table with core commands\n'
-        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
-        protos += '                                                             VkDevice dev);\n'
-        protos += '\n'
-        protos += '// Init Device function pointer dispatch table with extension commands\n'
-        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
-        protos += '                                                                       PFN_vkGetDeviceProcAddr gpa, VkDevice dev);\n'
-        protos += '\n'
-        protos += '// Init Instance function pointer dispatch table with core commands\n'
-        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
-        protos += '                                                                    VkInstance inst);\n'
-        protos += '\n'
-        protos += '// Init Instance function pointer dispatch table with core commands\n'
-        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
-        protos += '                                                                         VkInstance inst);\n'
-        protos += '\n'
-        protos += '// Device command lookup function\n'
-        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name);\n'
-        protos += '\n'
-        protos += '// Instance command lookup function\n'
-        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
-        protos += '                                                                  bool *found_name);\n'
-        protos += '\n'
-        protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
-        protos += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa);\n'
-        protos += '\n'
-        return protos
-
-    def OutputUtilitiesInSource(self):
-        protos = ''
-        protos += '// Device extension error function\n'
-        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev) {\n'
-        protos += '    struct loader_device *found_dev;\n'
-        protos += '    // The device going in is a trampoline device\n'
-        protos += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(dev, &found_dev, NULL);\n'
-        protos += '\n'
-        protos += '    if (icd_term)\n'
-        protos += '        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,\n'
-        protos += '                   "Bad destination in loader trampoline dispatch,"\n'
-        protos += '                   "Are layers and extensions that you are calling enabled?");\n'
-        protos += '    return VK_ERROR_EXTENSION_NOT_PRESENT;\n'
-        protos += '}\n\n'
-        return protos
-
-    #
-    # Create a layer instance dispatch table from the appropriate list and return it as a string
-    def OutputLayerInstanceDispatchTable(self):
-        commands = []
-        table = ''
-        cur_extension_name = ''
-
-        table += '// Instance function pointer dispatch table\n'
-        table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
-
-        # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
-        # ever show up in the XML or header, so we have to manually add it.
-        table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
-        table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
-
-        for x in range(0, 2):
-            if x == 0:
-                commands = self.core_commands
-            else:
-                commands = self.ext_commands
-
-            for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                if is_inst_handle_type:
-
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                        else:
-                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-
-                    if cur_cmd.protect is not None:
-                        table += '#ifdef %s\n' % cur_cmd.protect
-
-                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
-
-                    if cur_cmd.protect is not None:
-                        table += '#endif // %s\n' % cur_cmd.protect
-
-        table += '} VkLayerInstanceDispatchTable;\n\n'
-        return table
-
-    #
-    # Create a layer device dispatch table from the appropriate list and return it as a string
-    def OutputLayerDeviceDispatchTable(self):
-        commands = []
-        table = ''
-        cur_extension_name = ''
-
-        table += '// Device function pointer dispatch table\n'
-        table += 'typedef struct VkLayerDispatchTable_ {\n'
-
-        for x in range(0, 2):
-            if x == 0:
-                commands = self.core_commands
-            else:
-                commands = self.ext_commands
-
-            for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                if not is_inst_handle_type:
-
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                        else:
-                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-
-                    if cur_cmd.protect is not None:
-                        table += '#ifdef %s\n' % cur_cmd.protect
-
-                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
-
-                    if cur_cmd.protect is not None:
-                        table += '#endif // %s\n' % cur_cmd.protect
-
-        table += '} VkLayerDispatchTable;\n\n'
-        return table
-
-    #
-    # Create a dispatch table from the appropriate list and return it as a string
-    def OutputIcdDispatchTable(self):
-        commands = []
-        table = ''
-        cur_extension_name = ''
-
-        table += '// ICD function pointer dispatch table\n'
-        table += 'struct loader_icd_term_dispatch {\n'
-
-        for x in range(0, 2):
-            if x == 0:
-                commands = self.core_commands
-            else:
-                commands = self.ext_commands
-
-            for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and
-                    (cur_cmd.name != 'vkGetInstanceProcAddr' and cur_cmd.name != 'vkEnumerateDeviceLayerProperties')):
-
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                        else:
-                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-
-                    if cur_cmd.protect is not None:
-                        table += '#ifdef %s\n' % cur_cmd.protect
-
-                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
-
-                    if cur_cmd.protect is not None:
-                        table += '#endif // %s\n' % cur_cmd.protect
-
-        table += '};\n\n'
-        return table
-
-    #
-    # Init a dispatch table from the appropriate list and return it as a string
-    def OutputIcdDispatchTableInit(self):
-        commands = []
-        cur_extension_name = ''
-
-        table = ''
-        table += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
-        table += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa) {\n'
-        table += '\n'
-        table += '#define LOOKUP_GIPA(func, required)                                                        \\\n'
-        table += '    do {                                                                                   \\\n'
-        table += '        icd_term->dispatch.func = (PFN_vk##func)fp_gipa(inst, "vk" #func);                 \\\n'
-        table += '        if (!icd_term->dispatch.func && required) {                                        \\\n'
-        table += '            loader_log((struct loader_instance *)inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \\\n'
-        table += '                       loader_platform_get_proc_address_error("vk" #func));                \\\n'
-        table += '            return false;                                                                  \\\n'
-        table += '        }                                                                                  \\\n'
-        table += '    } while (0)\n'
-        table += '\n'
-
-        skip_gipa_commands = ['vkGetInstanceProcAddr',
-                              'vkEnumerateDeviceLayerProperties',
-                              'vkCreateInstance',
-                              'vkEnumerateInstanceExtensionProperties',
-                              'vkEnumerateInstanceLayerProperties',
-                              'vkEnumerateInstanceVersion',
-                             ]
-
-        for x in range(0, 2):
-            if x == 0:
-                commands = self.core_commands
-            else:
-                commands = self.ext_commands
-
-            required = False
-            for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and (cur_cmd.name not in skip_gipa_commands)):
-
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            table += '\n    // ---- Core %s\n' % cur_cmd.ext_name[11:]
-                            required = cur_cmd.ext_name == 'VK_VERSION_1_0'
-                        else:
-                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                            required = False
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-
-                    if cur_cmd.protect is not None:
-                        table += '#ifdef %s\n' % cur_cmd.protect
-
-                    # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
-                    # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
-                    table += '    LOOKUP_GIPA(%s, %s);\n' % (base_name, 'true' if required else 'false')
-
-                    if cur_cmd.protect is not None:
-                        table += '#endif // %s\n' % cur_cmd.protect
-
-        table += '\n'
-        table += '#undef LOOKUP_GIPA\n'
-        table += '\n'
-        table += '    return true;\n'
-        table += '};\n\n'
-        return table
-
-    #
-    # Create the extension enable union
-    def OutputIcdExtensionEnableUnion(self):
-        extensions = self.instanceExtensions
-
-        union = ''
-        union += 'union loader_instance_extension_enables {\n'
-        union += '    struct {\n'
-        for ext in extensions:
-            if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
-                ext.type == 'device' or ext.num_commands == 0):
-                continue
-
-            union += '        uint8_t %s : 1;\n' % ext.name[3:].lower()
-
-        union += '    };\n'
-        union += '    uint64_t padding[4];\n'
-        union += '};\n\n'
-        return union
-
-    #
-    # Creates the prototypes for the loader's core instance command terminators
-    def OutputLoaderTerminators(self):
-        terminators = ''
-        terminators += '// Loader core instance terminators\n'
-
-        for cur_cmd in self.core_commands:
-            is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-            if is_inst_handle_type:
-                mod_string = ''
-                new_terminator = cur_cmd.cdecl
-                mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_")
-
-                if cur_cmd.name in PRE_INSTANCE_FUNCTIONS:
-                    mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n    const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n')
-
-                if (cur_cmd.protect != None):
-                    terminators += '#ifdef %s\n' % cur_cmd.protect
-
-                terminators += mod_string
-                terminators += '\n'
-
-                if (cur_cmd.protect != None):
-                    terminators += '#endif // %s\n' % cur_cmd.protect
-
-        terminators += '\n'
-        return terminators
-
-    #
-    # Creates code to initialize the various dispatch tables
-    def OutputLoaderDispatchTables(self):
-        commands = []
-        tables = ''
-        gpa_param = ''
-        cur_type = ''
-        cur_extension_name = ''
-
-        for x in range(0, 4):
-            if x == 0:
-                cur_type = 'device'
-                gpa_param = 'dev'
-                commands = self.core_commands
-
-                tables += '// Init Device function pointer dispatch table with core commands\n'
-                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
-                tables += '                                                             VkDevice dev) {\n'
-                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
-                tables += '    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch.dev_ext[i] = (PFN_vkDevExt)vkDevExtError;\n'
-
-            elif x == 1:
-                cur_type = 'device'
-                gpa_param = 'dev'
-                commands = self.ext_commands
-
-                tables += '// Init Device function pointer dispatch table with extension commands\n'
-                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
-                tables += '                                                                       PFN_vkGetDeviceProcAddr gpa, VkDevice dev) {\n'
-                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
-
-            elif x == 2:
-                cur_type = 'instance'
-                gpa_param = 'inst'
-                commands = self.core_commands
-
-                tables += '// Init Instance function pointer dispatch table with core commands\n'
-                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
-                tables += '                                                                    VkInstance inst) {\n'
-
-            else:
-                cur_type = 'instance'
-                gpa_param = 'inst'
-                commands = self.ext_commands
-
-                tables += '// Init Instance function pointer dispatch table with core commands\n'
-                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
-                tables += '                                                                        VkInstance inst) {\n'
-
-            for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            tables += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                        else:
-                            tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-
-                    # Names to skip
-                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
-                        base_name == 'EnumerateInstanceExtensionProperties' or
-                        base_name == 'EnumerateInstanceLayerProperties' or
-                        base_name == 'EnumerateInstanceVersion'):
-                        continue
-
-                    if cur_cmd.protect is not None:
-                        tables += '#ifdef %s\n' % cur_cmd.protect
-
-                    # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
-                    # a layer overrides the function name for the loader.
-                    if (x <= 1 and base_name == 'GetDeviceProcAddr'):
-                        tables += '    table->GetDeviceProcAddr = gpa;\n'
-                    elif (x > 1 and base_name == 'GetInstanceProcAddr'):
-                        tables += '    table->GetInstanceProcAddr = gpa;\n'
-                    else:
-                        tables += '    table->%s = (PFN_%s)gpa(%s, "%s");\n' % (base_name, cur_cmd.name, gpa_param, cur_cmd.name)
-
-                    if cur_cmd.protect is not None:
-                        tables += '#endif // %s\n' % cur_cmd.protect
-
-            tables += '}\n\n'
-        return tables
-
-    #
-    # Create a lookup table function from the appropriate list of entrypoints and
-    # return it as a string
-    def OutputLoaderLookupFunc(self):
-        commands = []
-        tables = ''
-        cur_type = ''
-        cur_extension_name = ''
-
-        for x in range(0, 2):
-            if x == 0:
-                cur_type = 'device'
-
-                tables += '// Device command lookup function\n'
-                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name) {\n'
-                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') return NULL;\n'
-                tables += '\n'
-                tables += '    name += 2;\n'
-            else:
-                cur_type = 'instance'
-
-                tables += '// Instance command lookup function\n'
-                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
-                tables += '                                                                 bool *found_name) {\n'
-                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') {\n'
-                tables += '        *found_name = false;\n'
-                tables += '        return NULL;\n'
-                tables += '    }\n'
-                tables += '\n'
-                tables += '    *found_name = true;\n'
-                tables += '    name += 2;\n'
-
-            for y in range(0, 2):
-                if y == 0:
-                    commands = self.core_commands
-                else:
-                    commands = self.ext_commands
-
-                for cur_cmd in commands:
-                    is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
-                    if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
-
-                        if cur_cmd.ext_name != cur_extension_name:
-                            if 'VK_VERSION_' in cur_cmd.ext_name:
-                                tables += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                            else:
-                                tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                            cur_extension_name = cur_cmd.ext_name
-
-                        # Remove 'vk' from proto name
-                        base_name = cur_cmd.name[2:]
-
-                        if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
-                            base_name == 'EnumerateInstanceExtensionProperties' or
-                            base_name == 'EnumerateInstanceLayerProperties' or
-                            base_name == 'EnumerateInstanceVersion'):
-                            continue
-
-                        if cur_cmd.protect is not None:
-                            tables += '#ifdef %s\n' % cur_cmd.protect
-
-                        tables += '    if (!strcmp(name, "%s")) return (void *)table->%s;\n' % (base_name, base_name)
-
-                        if cur_cmd.protect is not None:
-                            tables += '#endif // %s\n' % cur_cmd.protect
-
-            tables += '\n'
-            if x == 1:
-                tables += '    *found_name = false;\n'
-            tables += '    return NULL;\n'
-            tables += '}\n\n'
-        return tables
-
-    #
-    # Create the appropriate trampoline (and possibly terminator) functinos
-    def CreateTrampTermFuncs(self):
-        entries = []
-        funcs = ''
-        cur_extension_name = ''
-
-        # Some extensions have to be manually added.  Skip those in the automatic
-        # generation.  They will be manually added later.
-        manual_ext_commands = ['vkEnumeratePhysicalDeviceGroupsKHR',
-                               'vkGetPhysicalDeviceExternalImageFormatPropertiesNV',
-                               'vkGetPhysicalDeviceFeatures2KHR',
-                               'vkGetPhysicalDeviceProperties2KHR',
-                               'vkGetPhysicalDeviceFormatProperties2KHR',
-                               'vkGetPhysicalDeviceImageFormatProperties2KHR',
-                               'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
-                               'vkGetPhysicalDeviceMemoryProperties2KHR',
-                               'vkGetPhysicalDeviceSparseImageFormatProperties2KHR',
-                               'vkGetPhysicalDeviceSurfaceCapabilities2KHR',
-                               'vkGetPhysicalDeviceSurfaceFormats2KHR',
-                               'vkGetPhysicalDeviceSurfaceCapabilities2EXT',
-                               'vkReleaseDisplayEXT',
-                               'vkAcquireXlibDisplayEXT',
-                               'vkGetRandROutputDisplayEXT',
-                               'vkGetPhysicalDeviceExternalBufferPropertiesKHR',
-                               'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR',
-                               'vkGetPhysicalDeviceExternalFencePropertiesKHR']
-
-        for ext_cmd in self.ext_commands:
-            if (ext_cmd.ext_name in WSI_EXT_NAMES or
-                ext_cmd.ext_name in AVOID_EXT_NAMES or
-                ext_cmd.name in AVOID_CMD_NAMES or
-                ext_cmd.name in manual_ext_commands):
-                continue
-
-            if ext_cmd.ext_name != cur_extension_name:
-                if 'VK_VERSION_' in ext_cmd.ext_name:
-                    funcs += '\n// ---- Core %s trampoline/terminators\n\n' % ext_cmd.ext_name[11:]
-                else:
-                    funcs += '\n// ---- %s extension trampoline/terminators\n\n' % ext_cmd.ext_name
-                cur_extension_name = ext_cmd.ext_name
-
-            if ext_cmd.protect is not None:
-                funcs += '#ifdef %s\n' % ext_cmd.protect
-
-            func_header = ext_cmd.cdecl.replace(";", " {\n")
-            tramp_header = func_header.replace("VKAPI_CALL vk", "VKAPI_CALL ")
-            return_prefix = '    '
-            base_name = ext_cmd.name[2:]
-            has_surface = 0
-            update_structure_surface = 0
-            update_structure_string = ''
-            requires_terminator = 0
-            surface_var_name = ''
-            phys_dev_var_name = ''
-            has_return_type = False
-            always_use_param_name = True
-            surface_type_to_replace = ''
-            surface_name_replacement = ''
-            physdev_type_to_replace = ''
-            physdev_name_replacement = ''
-
-            for param in ext_cmd.params:
-                if param.type == 'VkSurfaceKHR':
-                    has_surface = 1
-                    surface_var_name = param.name
-                    requires_terminator = 1
-                    always_use_param_name = False
-                    surface_type_to_replace = 'VkSurfaceKHR'
-                    surface_name_replacement = 'icd_surface->real_icd_surfaces[icd_index]'
-                if param.type == 'VkPhysicalDeviceSurfaceInfo2KHR':
-                    has_surface = 1
-                    surface_var_name = param.name + '->surface'
-                    requires_terminator = 1
-                    update_structure_surface = 1
-                    update_structure_string = '        VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;\n'
-                    update_structure_string += '        info_copy.surface = icd_surface->real_icd_surfaces[icd_index];\n'
-                    always_use_param_name = False
-                    surface_type_to_replace = 'VkPhysicalDeviceSurfaceInfo2KHR'
-                    surface_name_replacement = '&info_copy'
-                if param.type == 'VkPhysicalDevice':
-                    requires_terminator = 1
-                    phys_dev_var_name = param.name
-                    always_use_param_name = False
-                    physdev_type_to_replace = 'VkPhysicalDevice'
-                    physdev_name_replacement = 'phys_dev_term->phys_dev'
-
-            if (ext_cmd.return_type != None):
-                return_prefix += 'return '
-                has_return_type = True
-
-            if (ext_cmd.handle_type == 'VkInstance' or ext_cmd.handle_type == 'VkPhysicalDevice' or
-                'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or
-                ext_cmd.name in DEVICE_CMDS_NEED_TERM):
-                requires_terminator = 1
-
-            if requires_terminator == 1:
-                term_header = tramp_header.replace("VKAPI_CALL ", "VKAPI_CALL terminator_")
-
-                funcs += tramp_header
-
-                if ext_cmd.handle_type == 'VkPhysicalDevice':
-                    funcs += '    const VkLayerInstanceDispatchTable *disp;\n'
-                    funcs += '    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(%s);\n' % (phys_dev_var_name)
-                    funcs += '    disp = loader_get_instance_layer_dispatch(%s);\n' % (phys_dev_var_name)
-                elif ext_cmd.handle_type == 'VkInstance':
-                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
-                else:
-                    funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
-                    funcs += ext_cmd.params[0].name
-                    funcs += ');\n'
-
-                if 'DebugMarkerSetObjectName' in ext_cmd.name:
-                    funcs += '    VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
-                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
-                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                    funcs += '    if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
-                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->object;\n'
-                    funcs += '        local_name_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
-                    funcs += '    }\n'
-                elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
-                    funcs += '    VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
-                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
-                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                    funcs += '    if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
-                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n'
-                    funcs += '        local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
-                    funcs += '    }\n'
-                elif 'SetDebugUtilsObjectName' in ext_cmd.name:
-                    funcs += '    VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
-                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
-                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                    funcs += '    if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
-                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->objectHandle;\n'
-                    funcs += '        local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
-                    funcs += '    }\n'
-                elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
-                    funcs += '    VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
-                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
-                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                    funcs += '    if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
-                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->objectHandle;\n'
-                    funcs += '        local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
-                    funcs += '    }\n'
-
-                funcs += return_prefix
-                funcs += 'disp->'
-                funcs += base_name
-                funcs += '('
-                count = 0
-                for param in ext_cmd.params:
-                    if count != 0:
-                        funcs += ', '
-
-                    if param.type == 'VkPhysicalDevice':
-                        funcs += 'unwrapped_phys_dev'
-                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
-                            funcs += '&local_name_info'
-                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
-                            funcs += '&local_tag_info'
-                    else:
-                        funcs += param.name
-
-                    count += 1
-                funcs += ');\n'
-                funcs += '}\n\n'
-
-                funcs += term_header
-                if ext_cmd.handle_type == 'VkPhysicalDevice':
-                    funcs += '    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)%s;\n' % (phys_dev_var_name)
-                    funcs += '    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;\n'
-                    funcs += '    if (NULL == icd_term->dispatch.'
-                    funcs += base_name
-                    funcs += ') {\n'
-                    funcs += '        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,\n'
-                    funcs += '                   "ICD associated with VkPhysicalDevice does not support '
-                    funcs += base_name
-                    funcs += '");\n'
-                    funcs += '    }\n'
-
-                    if has_surface == 1:
-                        funcs += '    VkIcdSurface *icd_surface = (VkIcdSurface *)(%s);\n' % (surface_var_name)
-                        funcs += '    uint8_t icd_index = phys_dev_term->icd_index;\n'
-                        funcs += '    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)icd_surface->real_icd_surfaces[icd_index]) {\n'
-
-                        # If there's a structure with a surface, we need to update its internals with the correct surface for the ICD
-                        if update_structure_surface == 1:
-                            funcs += update_structure_string
-
-                        funcs += '    ' + return_prefix + 'icd_term->dispatch.'
-                        funcs += base_name
-                        funcs += '('
-                        count = 0
-                        for param in ext_cmd.params:
-                            if count != 0:
-                                funcs += ', '
-
-                            if not always_use_param_name:
-                                if surface_type_to_replace and surface_type_to_replace == param.type:
-                                    funcs += surface_name_replacement
-                                elif physdev_type_to_replace and physdev_type_to_replace == param.type:
-                                    funcs += physdev_name_replacement
-                                else:
-                                    funcs += param.name
-                            else:
-                                funcs += param.name
-
-                            count += 1
-                        funcs += ');\n'
-                        if not has_return_type:
-                            funcs += '        return;\n'
-                        funcs += '    }\n'
-
-                    funcs += return_prefix
-                    funcs += 'icd_term->dispatch.'
-                    funcs += base_name
-                    funcs += '('
-                    count = 0
-                    for param in ext_cmd.params:
-                        if count != 0:
-                            funcs += ', '
-
-                        if param.type == 'VkPhysicalDevice':
-                            funcs += 'phys_dev_term->phys_dev'
-                        else:
-                            funcs += param.name
-
-                        count += 1
-                    funcs += ');\n'
-
-                elif has_surface == 1 and not (ext_cmd.handle_type == 'VkPhysicalDevice' or ext_cmd.handle_type == 'VkInstance'):
-                    funcs += '    uint32_t icd_index = 0;\n'
-                    funcs += '    struct loader_device *dev;\n'
-                    funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);\n'
-                    funcs += '    if (NULL != icd_term && NULL != icd_term->dispatch.%s) {\n' % base_name
-                    funcs += '        VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s;\n' % (surface_var_name)
-                    funcs += '        if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {\n'
-                    funcs += '        %sicd_term->dispatch.%s(' % (return_prefix, base_name)
-                    count = 0
-                    for param in ext_cmd.params:
-                        if count != 0:
-                            funcs += ', '
-
-                        if param.type == 'VkSurfaceKHR':
-                            funcs += 'icd_surface->real_icd_surfaces[icd_index]'
-                        else:
-                            funcs += param.name
-
-                        count += 1
-                    funcs += ');\n'
-                    if not has_return_type:
-                        funcs += '                return;\n'
-                    funcs += '        }\n'
-                    funcs += '    %sicd_term->dispatch.%s(' % (return_prefix, base_name)
-                    count = 0
-                    for param in ext_cmd.params:
-                        if count != 0:
-                            funcs += ', '
-                        funcs += param.name
-                        count += 1
-                    funcs += ');\n'
-                    funcs += '    }\n'
-                    if has_return_type:
-                        funcs += '    return VK_SUCCESS;\n'
-
-                elif ext_cmd.handle_type == 'VkInstance':
-                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
-                elif 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name:
-                    funcs += '    uint32_t icd_index = 0;\n'
-                    funcs += '    struct loader_device *dev;\n'
-                    funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(%s, &dev, &icd_index);\n' % (ext_cmd.params[0].name)
-                    funcs += '    if (NULL != icd_term && NULL != icd_term->dispatch.'
-                    funcs += base_name
-                    funcs += ') {\n'
-                    if 'DebugMarkerSetObjectName' in ext_cmd.name:
-                        funcs += '        VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
-                        funcs += '        memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
-                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
-                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;\n'
-                        funcs += '            local_name_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
-                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
-                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
-                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;\n'
-                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
-                        funcs += '                    local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
-                        funcs += '                }\n'
-                    elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
-                        funcs += '        VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
-                        funcs += '        memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
-                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
-                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;\n'
-                        funcs += '            local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
-                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
-                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
-                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;\n'
-                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
-                        funcs += '                    local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
-                        funcs += '                }\n'
-                    elif 'SetDebugUtilsObjectName' in ext_cmd.name:
-                        funcs += '        VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
-                        funcs += '        memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
-                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
-                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;\n'
-                        funcs += '            local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
-                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
-                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
-                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;\n'
-                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
-                        funcs += '                    local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
-                        funcs += '                }\n'
-                    elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
-                        funcs += '        VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
-                        funcs += '        memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
-                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
-                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;\n'
-                        funcs += '            local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
-                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
-                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
-                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;\n'
-                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
-                        funcs += '                    local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
-                        funcs += '                }\n'
-                    else:
-                        funcs += '        if (%s->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' % (ext_cmd.params[1].name)
-                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)%s->objectHandle;\n' % (ext_cmd.params[1].name)
-                        funcs += '            %s->objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n' % (ext_cmd.params[1].name)
-                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
-                        funcs += '        } else if (%s->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n' % (ext_cmd.params[1].name)
-                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
-                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s->objectHandle;\n' % (ext_cmd.params[1].name)
-                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
-                        funcs += '                    %s->objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n' % (ext_cmd.params[1].name)
-                        funcs += '                }\n'
-                    funcs += '            }\n'
-                    funcs += '        }\n'
-                    funcs += '        return icd_term->dispatch.'
-                    funcs += base_name
-                    funcs += '('
-                    count = 0
-                    for param in ext_cmd.params:
-                        if count != 0:
-                            funcs += ', '
-
-                        if param.type == 'VkPhysicalDevice':
-                            funcs += 'phys_dev_term->phys_dev'
-                        elif param.type == 'VkSurfaceKHR':
-                            funcs += 'icd_surface->real_icd_surfaces[icd_index]'
-                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
-                            funcs += '&local_name_info'
-                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
-                            funcs += '&local_tag_info'
-                        else:
-                            funcs += param.name
-                        count += 1
-
-                    funcs += ');\n'
-                    funcs += '    } else {\n'
-                    funcs += '        return VK_SUCCESS;\n'
-                    funcs += '    }\n'
-
-                else:
-                    funcs += '#error("Unknown error path!");\n'
-
-                funcs += '}\n\n'
-            else:
-                funcs += tramp_header
-
-                funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
-                funcs += ext_cmd.params[0].name
-                funcs += ');\n'
-
-                funcs += return_prefix
-                funcs += 'disp->'
-                funcs += base_name
-                funcs += '('
-                count = 0
-                for param in ext_cmd.params:
-                    if count != 0:
-                        funcs += ', '
-                    funcs += param.name
-                    count += 1
-                funcs += ');\n'
-                funcs += '}\n\n'
-
-            if ext_cmd.protect is not None:
-                funcs += '#endif // %s\n' % ext_cmd.protect
-
-        return funcs
-
-
-    #
-    # Create a function for the extension GPA call
-    def InstExtensionGPA(self):
-        entries = []
-        gpa_func = ''
-        cur_extension_name = ''
-
-        gpa_func += '// GPA helpers for extensions\n'
-        gpa_func += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {\n'
-        gpa_func += '    *addr = NULL;\n\n'
-
-        for cur_cmd in self.ext_commands:
-            if ('VK_VERSION_' in cur_cmd.ext_name or
-                cur_cmd.ext_name in WSI_EXT_NAMES or
-                cur_cmd.ext_name in AVOID_EXT_NAMES or
-                cur_cmd.name in AVOID_CMD_NAMES ):
-                continue
-
-            if cur_cmd.ext_name != cur_extension_name:
-                gpa_func += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                cur_extension_name = cur_cmd.ext_name
-
-            if cur_cmd.protect is not None:
-                gpa_func += '#ifdef %s\n' % cur_cmd.protect
-
-            #base_name = cur_cmd.name[2:]
-            base_name = ALIASED_CMDS[cur_cmd.name] if cur_cmd.name in ALIASED_CMDS else cur_cmd.name[2:]
-
-            if (cur_cmd.ext_type == 'instance'):
-                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
-                gpa_func += '        *addr = (ptr_instance->enabled_known_extensions.'
-                gpa_func += cur_cmd.ext_name[3:].lower()
-                gpa_func += ' == 1)\n'
-                gpa_func += '                     ? (void *)%s\n' % (base_name)
-                gpa_func += '                     : NULL;\n'
-                gpa_func += '        return true;\n'
-                gpa_func += '    }\n'
-            else:
-                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
-                gpa_func += '        *addr = (void *)%s;\n' % (base_name)
-                gpa_func += '        return true;\n'
-                gpa_func += '    }\n'
-
-            if cur_cmd.protect is not None:
-                gpa_func += '#endif // %s\n' % cur_cmd.protect
-
-        gpa_func += '    return false;\n'
-        gpa_func += '}\n\n'
-
-        return gpa_func
-
-    #
-    # Create the extension name init function
-    def InstantExtensionCreate(self):
-        entries = []
-        entries = self.instanceExtensions
-        count = 0
-        cur_extension_name = ''
-
-        create_func = ''
-        create_func += '// A function that can be used to query enabled extensions during a vkCreateInstance call\n'
-        create_func += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {\n'
-        create_func += '    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n'
-        for ext in entries:
-            if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
-                ext.name in AVOID_EXT_NAMES or ext.name in AVOID_CMD_NAMES or
-                ext.type == 'device' or ext.num_commands == 0):
-                continue
-
-            if ext.name != cur_extension_name:
-                create_func += '\n    // ---- %s extension commands\n' % ext.name
-                cur_extension_name = ext.name
-
-            if ext.protect is not None:
-                create_func += '#ifdef %s\n' % ext.protect
-            if count == 0:
-                create_func += '        if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
-            else:
-                create_func += '        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
-
-            create_func += ext.define + ')) {\n'
-            create_func += '            ptr_instance->enabled_known_extensions.'
-            create_func += ext.name[3:].lower()
-            create_func += ' = 1;\n'
-
-            if ext.protect is not None:
-                create_func += '#endif // %s\n' % ext.protect
-            count += 1
-
-        create_func += '        }\n'
-        create_func += '    }\n'
-        create_func += '}\n\n'
-        return create_func
-
-    #
-    # Create code to initialize a dispatch table from the appropriate list of
-    # extension entrypoints and return it as a string
-    def DeviceExtensionGetTerminator(self):
-        term_func = ''
-        cur_extension_name = ''
-
-        term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n'
-        term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object.  But there may be other items\n'
-        term_func += '// in the future.\n'
-        term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *pName) {\n'
-        term_func += '    PFN_vkVoidFunction addr = NULL;\n'
-
-        count = 0
-        is_extension = False
-        for ext_cmd in self.ext_commands:
-            if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
-                if ext_cmd.ext_name != cur_extension_name:
-                    if count > 0:
-                        count = 0;
-                        term_func += '        }\n'
-                    if is_extension:
-                        term_func += '    }\n'
-                        is_extension = False
-
-                    if 'VK_VERSION_' in ext_cmd.ext_name:
-                        term_func += '\n    // ---- Core %s commands\n' % ext_cmd.ext_name[11:]
-                    else:
-                        term_func += '\n    // ---- %s extension commands\n' % ext_cmd.ext_name
-                        term_func += '    if (dev->extensions.%s_enabled) {\n' % ext_cmd.ext_name[3:].lower()
-                        is_extension = True
-                    cur_extension_name = ext_cmd.ext_name
-
-                if ext_cmd.protect is not None:
-                    term_func += '#ifdef %s\n' % ext_cmd.protect
-
-                if count == 0:
-                    term_func += '        if'
-                else:
-                    term_func += '        } else if'
-                term_func += '(!strcmp(pName, "%s")) {\n' % (ext_cmd.name)
-                term_func += '            addr = (PFN_vkVoidFunction)terminator_%s;\n' % (ext_cmd.name[2:])
-
-                if ext_cmd.protect is not None:
-                    term_func += '#endif // %s\n' % ext_cmd.protect
-
-                count += 1
-
-        if count > 0:
-            term_func += '        }\n'
-        if is_extension:
-            term_func += '    }\n'
-
-        term_func += '    return addr;\n'
-        term_func += '}\n\n'
-
-        return term_func
-
-    #
-    # Create code to initialize a dispatch table from the appropriate list of
-    # core and extension entrypoints and return it as a string
-    def InitInstLoaderExtensionDispatchTable(self):
-        commands = []
-        table = ''
-        cur_extension_name = ''
-
-        table += '// This table contains the loader\'s instance dispatch table, which contains\n'
-        table += '// default functions if no instance layers are activated.  This contains\n'
-        table += '// pointers to "terminator functions".\n'
-        table += 'const VkLayerInstanceDispatchTable instance_disp = {\n'
-
-        for x in range(0, 2):
-            if x == 0:
-                commands = self.core_commands
-            else:
-                commands = self.ext_commands
-
-            for cur_cmd in commands:
-                
-                if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice':
-                    if cur_cmd.ext_name != cur_extension_name:
-                        if 'VK_VERSION_' in cur_cmd.ext_name:
-                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
-                        else:
-                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
-                        cur_extension_name = cur_cmd.ext_name
-
-                    # Remove 'vk' from proto name
-                    base_name = cur_cmd.name[2:]
-                    aliased_name = ALIASED_CMDS[cur_cmd.name][2:] if cur_cmd.name in ALIASED_CMDS else base_name
-
-                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
-                        base_name == 'EnumerateInstanceExtensionProperties' or
-                        base_name == 'EnumerateInstanceLayerProperties' or
-                        base_name == 'EnumerateInstanceVersion'):
-                        continue
-
-                    if cur_cmd.protect is not None:
-                        table += '#ifdef %s\n' % cur_cmd.protect
-
-                    if base_name == 'GetInstanceProcAddr':
-                        table += '    .%s = %s,\n' % (base_name, cur_cmd.name)
-                    else:
-                        table += '    .%s = terminator_%s,\n' % (base_name, aliased_name)
-
-                    if cur_cmd.protect is not None:
-                        table += '#endif // %s\n' % cur_cmd.protect
-        table += '};\n\n'
-
-        return table
-
-    #
-    # Create the extension name whitelist array
-    def OutputInstantExtensionWhitelistArray(self):
-        extensions = self.instanceExtensions
-
-        table = ''
-        table += '// A null-terminated list of all of the instance extensions supported by the loader.\n'
-        table += '// If an instance extension name is not in this list, but it is exported by one or more of the\n'
-        table += '// ICDs detected by the loader, then the extension name not in the list will be filtered out\n'
-        table += '// before passing the list of extensions to the application.\n'
-        table += 'const char *const LOADER_INSTANCE_EXTENSIONS[] = {\n'
-        for ext in extensions:
-            if ext.type == 'device' or 'VK_VERSION_' in ext.name:
-                continue
-
-            if ext.protect is not None:
-                table += '#ifdef %s\n' % ext.protect
-            table += '                                                  '
-            table += ext.define + ',\n'
-
-            if ext.protect is not None:
-                table += '#endif // %s\n' % ext.protect
-        table += '                                                  NULL };\n'
-        return table
-
diff --git a/scripts/lvl_genvk.py b/scripts/lvl_genvk.py
index 3ed5c0d..50d0294 100644
--- a/scripts/lvl_genvk.py
+++ b/scripts/lvl_genvk.py
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 #
-# Copyright (c) 2013-2018 The Khronos Group Inc.
+# Copyright (c) 2013-2019 The Khronos Group Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -21,18 +21,19 @@
 
 def startTimer(timeit):
     global startTime
-    startTime = time.clock()
+    if timeit:
+        startTime = time.process_time()
 
 def endTimer(timeit, msg):
     global startTime
-    endTime = time.clock()
-    if (timeit):
+    if timeit:
+        endTime = time.process_time()
         write(msg, endTime - startTime, file=sys.stderr)
         startTime = None
 
 # Turn a list of strings into a regexp string matching exactly those strings
 def makeREstring(list, default = None):
-    if len(list) > 0 or default == None:
+    if len(list) > 0 or default is None:
         return '^(' + '|'.join(list) + ')$'
     else:
         return default
@@ -81,7 +82,7 @@
     # Copyright text prefixing all headers (list of strings).
     prefixStrings = [
         '/*',
-        '** Copyright (c) 2015-2018 The Khronos Group Inc.',
+        '** Copyright (c) 2015-2019 The Khronos Group Inc.',
         '**',
         '** Licensed under the Apache License, Version 2.0 (the "License");',
         '** you may not use this file except in compliance with the License.',
@@ -111,11 +112,11 @@
     protectFeature = protect
 
     # ValidationLayer Generators
-    # Options for threading layer
-    genOpts['thread_check.h'] = [
+    # Options for thread safety header code-generation
+    genOpts['thread_safety.h'] = [
           ThreadOutputGenerator,
           ThreadGeneratorOptions(
-            filename          = 'thread_check.h',
+            filename          = 'thread_safety.h',
             directory         = directory,
             apiname           = 'vulkan',
             profile           = None,
@@ -134,7 +135,30 @@
             expandEnumerants = False)
         ]
 
-    # Options for parameter validation layer
+    # Options for thread safety source code-generation
+    genOpts['thread_safety.cpp'] = [
+          ThreadOutputGenerator,
+          ThreadGeneratorOptions(
+            filename          = 'thread_safety.cpp',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            protectFeature    = False,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            expandEnumerants = False)
+        ]
+
+    # Options for stateless validation source file
     genOpts['parameter_validation.cpp'] = [
           ParameterValidationOutputGenerator,
           ParameterValidationGeneratorOptions(
@@ -157,11 +181,34 @@
             valid_usage_path  = args.scripts)
           ]
 
-    # Options for unique objects layer
-    genOpts['unique_objects_wrappers.h'] = [
-          UniqueObjectsOutputGenerator,
-          UniqueObjectsGeneratorOptions(
-            filename          = 'unique_objects_wrappers.h',
+    # Options for stateless validation source file
+    genOpts['parameter_validation.h'] = [
+          ParameterValidationOutputGenerator,
+          ParameterValidationGeneratorOptions(
+            filename          = 'parameter_validation.h',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            expandEnumerants  = False,
+            valid_usage_path  = args.scripts)
+          ]
+
+    # Options for object_tracker code-generated validation routines
+    genOpts['object_tracker.cpp'] = [
+          ObjectTrackerOutputGenerator,
+          ObjectTrackerGeneratorOptions(
+            filename          = 'object_tracker.cpp',
             directory         = directory,
             apiname           = 'vulkan',
             profile           = None,
@@ -177,14 +224,15 @@
             apientry          = 'VKAPI_CALL ',
             apientryp         = 'VKAPI_PTR *',
             alignFuncParam    = 48,
-            expandEnumerants = False)
+            expandEnumerants  = False,
+            valid_usage_path  = args.scripts)
         ]
 
-    # Options for object_tracker layer
-    genOpts['object_tracker.cpp'] = [
+    # Options for object_tracker code-generated prototypes
+    genOpts['object_tracker.h'] = [
           ObjectTrackerOutputGenerator,
           ObjectTrackerGeneratorOptions(
-            filename          = 'object_tracker.cpp',
+            filename          = 'object_tracker.h',
             directory         = directory,
             apiname           = 'vulkan',
             profile           = None,
@@ -228,8 +276,8 @@
 
     # Options for Layer dispatch table generator
     genOpts['vk_layer_dispatch_table.h'] = [
-          LoaderExtensionOutputGenerator,
-          LoaderExtensionGeneratorOptions(
+          LayerDispatchTableOutputGenerator,
+          LayerDispatchTableGeneratorOptions(
             filename          = 'vk_layer_dispatch_table.h',
             directory         = directory,
             apiname           = 'vulkan',
@@ -387,6 +435,100 @@
             helper_file_type  = 'typemap_helper_header')
         ]
 
+    # Layer chassis related generation structs
+    # Options for layer chassis header
+    genOpts['chassis.h'] = [
+          LayerChassisOutputGenerator,
+          LayerChassisGeneratorOptions(
+            filename          = 'chassis.h',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            helper_file_type  = 'layer_chassis_header',
+            expandEnumerants = False)
+        ]
+
+    # Options for layer chassis source file
+    genOpts['chassis.cpp'] = [
+          LayerChassisOutputGenerator,
+          LayerChassisGeneratorOptions(
+            filename          = 'chassis.cpp',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            helper_file_type  = 'layer_chassis_source',
+            expandEnumerants = False)
+        ]
+
+    # Options for layer chassis dispatch source file
+    genOpts['layer_chassis_dispatch.cpp'] = [
+          LayerChassisDispatchOutputGenerator,
+          LayerChassisDispatchGeneratorOptions(
+            filename          = 'layer_chassis_dispatch.cpp',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            protectFeature    = False,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            expandEnumerants = False)
+        ]
+
+    # Options for layer chassis dispatch header file
+    genOpts['layer_chassis_dispatch.h'] = [
+          LayerChassisDispatchOutputGenerator,
+          LayerChassisDispatchGeneratorOptions(
+            filename          = 'layer_chassis_dispatch.h',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = featuresPat,
+            emitversions      = featuresPat,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensionsPat,
+            removeExtensions  = removeExtensionsPat,
+            emitExtensions    = emitExtensionsPat,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            protectFeature    = False,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            expandEnumerants = False)
+        ]
+
+
 # Generate a target based on the options in the matching genOpts{} object.
 # 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
@@ -497,13 +639,14 @@
     from cgenerator import CGeneratorOptions, COutputGenerator
 
     # ValidationLayer Generator Modifications
-    from threading_generator import  ThreadGeneratorOptions, ThreadOutputGenerator
+    from thread_safety_generator import  ThreadGeneratorOptions, ThreadOutputGenerator
     from parameter_validation_generator import ParameterValidationGeneratorOptions, ParameterValidationOutputGenerator
-    from unique_objects_generator import UniqueObjectsGeneratorOptions, UniqueObjectsOutputGenerator
     from object_tracker_generator import ObjectTrackerGeneratorOptions, ObjectTrackerOutputGenerator
     from dispatch_table_helper_generator import DispatchTableHelperOutputGenerator, DispatchTableHelperOutputGeneratorOptions
     from helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
-    from loader_extension_generator import LoaderExtensionOutputGenerator, LoaderExtensionGeneratorOptions
+    from layer_dispatch_table_generator import LayerDispatchTableOutputGenerator, LayerDispatchTableGeneratorOptions
+    from layer_chassis_generator import LayerChassisOutputGenerator, LayerChassisGeneratorOptions
+    from layer_chassis_dispatch_generator import LayerChassisDispatchOutputGenerator, LayerChassisDispatchGeneratorOptions
 
     # This splits arguments which are space-separated lists
     args.feature = [name for arg in args.feature for name in arg.split()]
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 8608605..2176df2 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -1,9 +1,9 @@
 #!/usr/bin/python3 -i
 #
-# Copyright (c) 2015-2018 The Khronos Group Inc.
-# Copyright (c) 2015-2018 Valve Corporation
-# Copyright (c) 2015-2018 LunarG, Inc.
-# Copyright (c) 2015-2018 Google Inc.
+# Copyright (c) 2015-2019 The Khronos Group Inc.
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -127,71 +127,38 @@
                  diagFile = sys.stdout):
         OutputGenerator.__init__(self, errFile, warnFile, diagFile)
         self.INDENT_SPACES = 4
-        self.intercepts = []
+        self.prototypes = []
         self.instance_extensions = []
         self.device_extensions = []
         # Commands which are not autogenerated but still intercepted
         self.no_autogen_list = [
             'vkDestroyInstance',
-            'vkDestroyDevice',
-            'vkUpdateDescriptorSets',
-            'vkDestroyDebugReportCallbackEXT',
-            'vkDebugReportMessageEXT',
-            'vkGetPhysicalDeviceQueueFamilyProperties',
-            'vkFreeCommandBuffers',
-            'vkDestroySwapchainKHR',
-            'vkDestroyDescriptorPool',
-            'vkDestroyCommandPool',
-            'vkGetPhysicalDeviceQueueFamilyProperties2',
-            'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
-            'vkResetDescriptorPool',
-            'vkBeginCommandBuffer',
-            'vkCreateDebugReportCallbackEXT',
-            'vkEnumerateInstanceLayerProperties',
-            'vkEnumerateDeviceLayerProperties',
-            'vkEnumerateInstanceExtensionProperties',
-            'vkEnumerateDeviceExtensionProperties',
-            'vkCreateDevice',
             'vkCreateInstance',
             'vkEnumeratePhysicalDevices',
+            'vkGetPhysicalDeviceQueueFamilyProperties',
+            'vkGetPhysicalDeviceQueueFamilyProperties2',
+            'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
+            'vkGetDeviceQueue',
+            'vkGetDeviceQueue2',
+            'vkCreateDescriptorSetLayout',
+            'vkDestroyDescriptorPool',
+            'vkDestroyCommandPool',
             'vkAllocateCommandBuffers',
             'vkAllocateDescriptorSets',
             'vkFreeDescriptorSets',
-            'vkCmdPushDescriptorSetKHR',
-            'vkDebugMarkerSetObjectNameEXT',
-            'vkGetPhysicalDeviceProcAddr',
-            'vkGetDeviceProcAddr',
-            'vkGetInstanceProcAddr',
-            'vkEnumerateInstanceExtensionProperties',
-            'vkEnumerateInstanceLayerProperties',
-            'vkEnumerateDeviceLayerProperties',
-            'vkGetDeviceProcAddr',
-            'vkGetInstanceProcAddr',
-            'vkEnumerateDeviceExtensionProperties',
-            'vk_layerGetPhysicalDeviceProcAddr',
-            'vkNegotiateLoaderLayerInterfaceVersion',
-            'vkCreateComputePipelines',
-            'vkGetDeviceQueue',
-            'vkGetDeviceQueue2',
-            'vkGetSwapchainImagesKHR',
-            'vkCreateDescriptorSetLayout',
+            'vkFreeCommandBuffers',
+            'vkUpdateDescriptorSets',
+            'vkBeginCommandBuffer',
             'vkGetDescriptorSetLayoutSupport',
             'vkGetDescriptorSetLayoutSupportKHR',
-            'vkCreateDebugUtilsMessengerEXT',
-            'vkDestroyDebugUtilsMessengerEXT',
-            'vkSubmitDebugUtilsMessageEXT',
-            'vkSetDebugUtilsObjectNameEXT',
-            'vkSetDebugUtilsObjectTagEXT',
-            'vkQueueBeginDebugUtilsLabelEXT',
-            'vkQueueEndDebugUtilsLabelEXT',
-            'vkQueueInsertDebugUtilsLabelEXT',
-            'vkCmdBeginDebugUtilsLabelEXT',
-            'vkCmdEndDebugUtilsLabelEXT',
-            'vkCmdInsertDebugUtilsLabelEXT',
-            'vkGetDisplayModePropertiesKHR',
+            'vkDestroySwapchainKHR',
+            'vkGetSwapchainImagesKHR',
+            'vkCmdPushDescriptorSetKHR',
+            'vkDestroyDevice',
+            'vkResetDescriptorPool',
             'vkGetPhysicalDeviceDisplayPropertiesKHR',
             'vkGetPhysicalDeviceDisplayProperties2KHR',
-            'vkGetDisplayPlaneSupportedDisplaysKHR',
+            'vkGetDisplayModePropertiesKHR',
             'vkGetDisplayModeProperties2KHR',
             ]
         # These VUIDS are not implicit, but are best handled in this layer. Codegen for vkDestroy calls will generate a key
@@ -326,11 +293,13 @@
     # Generate the object tracker undestroyed object validation function
     def GenReportFunc(self):
         output_func = ''
-        output_func += 'void ReportUndestroyedObjects(VkDevice device, const std::string& error_code) {\n'
-        output_func += '    DeviceReportUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer, error_code);\n'
+        output_func += 'bool ObjectLifetimes::ReportUndestroyedObjects(VkDevice device, const std::string& error_code) {\n'
+        output_func += '    bool skip = false;\n'
+        output_func += '    skip |= DeviceReportUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer, error_code);\n'
         for handle in self.object_types:
             if self.isHandleTypeNonDispatchable(handle):
-                output_func += '    DeviceReportUndestroyedObjects(device, %s, error_code);\n' % (self.GetVulkanObjType(handle))
+                output_func += '    skip |= DeviceReportUndestroyedObjects(device, %s, error_code);\n' % (self.GetVulkanObjType(handle))
+        output_func += '    return skip;\n'
         output_func += '}\n'
         return output_func
 
@@ -338,7 +307,7 @@
     # Generate the object tracker undestroyed object destruction function
     def GenDestroyFunc(self):
         output_func = ''
-        output_func += 'void DestroyUndestroyedObjects(VkDevice device) {\n'
+        output_func += 'void ObjectLifetimes::DestroyUndestroyedObjects(VkDevice device) {\n'
         output_func += '    DeviceDestroyUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer);\n'
         for handle in self.object_types:
             if self.isHandleTypeNonDispatchable(handle):
@@ -360,12 +329,26 @@
                     for l in v:
                         for s in self.ExtractVUIDs(l):
                             yield s
+    #
+    # Separate content for validation source and header files
+    def otwrite(self, dest, formatstring):
+        if 'object_tracker.h' in self.genOpts.filename and (dest == 'hdr' or dest == 'both'):
+            write(formatstring, file=self.outFile)
+        elif 'object_tracker.cpp' in self.genOpts.filename and (dest == 'cpp' or dest == 'both'):
+            write(formatstring, file=self.outFile)
 
     #
     # Called at beginning of processing as file is opened
     def beginFile(self, genOpts):
         OutputGenerator.beginFile(self, genOpts)
 
+        header_file = (genOpts.filename == 'object_tracker.h')
+        source_file = (genOpts.filename == 'object_tracker.cpp')
+
+        if not header_file and not source_file:
+            print("Error: Output Filenames have changed, update generator source.\n")
+            sys.exit(1)
+
         self.valid_usage_path = genOpts.valid_usage_path
         vu_json_filename = os.path.join(self.valid_usage_path + os.sep, 'validusage.json')
         if os.path.isfile(vu_json_filename):
@@ -383,16 +366,16 @@
         # File Comment
         file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
         file_comment += '// See object_tracker_generator.py for modifications\n'
-        write(file_comment, file=self.outFile)
+        self.otwrite('both', file_comment)
         # Copyright Statement
         copyright = ''
         copyright += '\n'
         copyright += '/***************************************************************************\n'
         copyright += ' *\n'
-        copyright += ' * Copyright (c) 2015-2018 The Khronos Group Inc.\n'
-        copyright += ' * Copyright (c) 2015-2018 Valve Corporation\n'
-        copyright += ' * Copyright (c) 2015-2018 LunarG, Inc.\n'
-        copyright += ' * Copyright (c) 2015-2018 Google Inc.\n'
+        copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n'
+        copyright += ' * Copyright (c) 2015-2019 Valve Corporation\n'
+        copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n'
+        copyright += ' * Copyright (c) 2015-2019 Google Inc.\n'
         copyright += ' *\n'
         copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
         copyright += ' * you may not use this file except in compliance with the License.\n'
@@ -410,12 +393,11 @@
         copyright += ' * Author: Dave Houlton <daveh@lunarg.com>\n'
         copyright += ' *\n'
         copyright += ' ****************************************************************************/\n'
-        write(copyright, file=self.outFile)
-        # Namespace
+        self.otwrite('both', copyright)
         self.newline()
-        write('#include "object_tracker.h"', file = self.outFile)
-        self.newline()
-        write('namespace object_tracker {', file = self.outFile)
+        self.otwrite('cpp', '#include "chassis.h"')
+        self.otwrite('cpp', '#include "object_lifetime_validation.h"')
+
     #
     # Now that the data is all collected and complete, generate and output the object validation routines
     def endFile(self):
@@ -428,31 +410,38 @@
         self.newline()
         # Build undestroyed objects destruction function
         destroy_func = self.GenDestroyFunc()
-        self.newline()
-        write('// ObjectTracker undestroyed objects validation function', file=self.outFile)
-        write('%s' % report_func, file=self.outFile)
-        write('%s' % destroy_func, file=self.outFile)
+        self.otwrite('cpp', '\n')
+        self.otwrite('cpp', '// ObjectTracker undestroyed objects validation function')
+        self.otwrite('cpp', '%s' % report_func)
+        self.otwrite('cpp', '%s' % destroy_func)
         # Actually write the interface to the output file.
         if (self.emit):
             self.newline()
-            if (self.featureExtraProtect != None):
-                write('#ifdef', self.featureExtraProtect, file=self.outFile)
-            # Write the object_tracker code to the file
-            if (self.sections['command']):
-                write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
-            if (self.featureExtraProtect != None):
-                write('\n#endif //', self.featureExtraProtect, file=self.outFile)
+            if self.featureExtraProtect is not None:
+                prot = '#ifdef %s' % self.featureExtraProtect
+                self.otwrite('both', '%s' % prot)
+            # Write the object_tracker code to the  file
+            if self.sections['command']:
+                source = ('\n'.join(self.sections['command']))
+                self.otwrite('both', '%s' % source)
+            if (self.featureExtraProtect is not None):
+                prot = '\n#endif // %s', self.featureExtraProtect
+                self.otwrite('both', prot)
             else:
-                self.newline()
+                self.otwrite('both', '\n')
 
-        # Record intercepted procedures
-        write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
-        write('\n'.join(self.intercepts), file=self.outFile)
-        write('};\n', file=self.outFile)
-        self.newline()
-        write('} // namespace object_tracker', file=self.outFile)
-        # Finish processing in superclass
+
+        self.otwrite('hdr', 'void PostCallRecordDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator);')
+        self.otwrite('hdr', 'void PreCallRecordResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);')
+        self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties);')
+        self.otwrite('hdr', 'void PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);')
+        self.otwrite('hdr', 'void PreCallRecordFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets);')
+        self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);')
+        self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties);')
+        self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties, VkResult result);')
+        self.otwrite('hdr', 'void PostCallRecordGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties, VkResult result);')
+        self.otwrite('hdr', 'void PostCallRecordGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayProperties2KHR *pProperties, VkResult result);')
+        self.otwrite('hdr', 'void PostCallRecordGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, VkDisplayModeProperties2KHR *pProperties, VkResult result);')
         OutputGenerator.endFile(self)
     #
     # Processing point at beginning of each extension definition
@@ -464,10 +453,10 @@
 
         if self.featureName != 'VK_VERSION_1_0' and self.featureName != 'VK_VERSION_1_1':
             white_list_entry = []
-            if (self.featureExtraProtect != None):
+            if (self.featureExtraProtect is not None):
                 white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ]
             white_list_entry += [ '"%s"' % self.featureName ]
-            if (self.featureExtraProtect != None):
+            if (self.featureExtraProtect is not None):
                 white_list_entry += [ '#endif' ]
             featureType = interface.get('type')
             if featureType == 'instance':
@@ -624,8 +613,9 @@
         for member in struct_members:
             if self.isHandleTypeObject(member.type):
                 return True
-            elif member.type in struct_member_dict:
-                if self.struct_contains_object(member.type) == True:
+            # recurse for member structs, guard against infinite recursion
+            elif member.type in struct_member_dict and member.type != struct_item:
+                if self.struct_contains_object(member.type):
                     return True
         return False
     #
@@ -688,31 +678,40 @@
     def generate_create_object_code(self, indent, proto, params, cmd_info, allocator):
         create_obj_code = ''
         handle_type = params[-1].find('type')
+        is_create_pipelines = False
+
         if self.isHandleTypeObject(handle_type.text):
             # Check for special case where multiple handles are returned
             object_array = False
             if cmd_info[-1].len is not None:
                 object_array = True;
             handle_name = params[-1].find('name')
-            create_obj_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
-            indent = self.incIndent(indent)
-            create_obj_code += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
             object_dest = '*%s' % handle_name.text
             if object_array == True:
-                create_obj_code += '%sfor (uint32_t index = 0; index < %s; index++) {\n' % (indent, cmd_info[-1].len)
+                if 'CreateGraphicsPipelines' in proto.text or 'CreateComputePipelines' in proto.text or 'CreateRayTracingPipelines' in proto.text:
+                    is_create_pipelines = True
+                    create_obj_code += '%sif (VK_ERROR_VALIDATION_FAILED_EXT == result) return;\n' % indent
+                countispointer = ''
+                if 'uint32_t*' in cmd_info[-2].cdecl:
+                    countispointer = '*'
+                create_obj_code += '%sfor (uint32_t index = 0; index < %s%s; index++) {\n' % (indent, countispointer, cmd_info[-1].len)
                 indent = self.incIndent(indent)
                 object_dest = '%s[index]' % cmd_info[-1].name
+
+            dispobj = params[0].find('type').text
+            if is_create_pipelines:
+                create_obj_code += '%sif (!pPipelines[index]) continue;\n' % indent
             create_obj_code += '%sCreateObject(%s, %s, %s, %s);\n' % (indent, params[0].find('name').text, object_dest, self.GetVulkanObjType(cmd_info[-1].type), allocator)
             if object_array == True:
                 indent = self.decIndent(indent)
                 create_obj_code += '%s}\n' % indent
             indent = self.decIndent(indent)
-            create_obj_code += '%s}\n' % (indent)
         return create_obj_code
     #
     # Generate source for destroying a non-dispatchable object
     def generate_destroy_object_code(self, indent, proto, cmd_info):
-        destroy_obj_code = ''
+        validate_code = ''
+        record_code = ''
         object_array = False
         if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free']]:
             # Check for special case where multiple handles are returned
@@ -728,21 +727,17 @@
             if self.isHandleTypeObject(cmd_info[param].type) == True:
                 if object_array == True:
                     # This API is freeing an array of handles -- add loop control
-                    destroy_obj_code += 'HEY, NEED TO DESTROY AN ARRAY\n'
+                    validate_code += 'HEY, NEED TO DESTROY AN ARRAY\n'
                 else:
+                    dispobj = cmd_info[0].type
                     # Call Destroy a single time
-                    destroy_obj_code += '%sif (skip) return;\n' % indent
-                    destroy_obj_code += '%s{\n' % indent
-                    destroy_obj_code += '%s    std::lock_guard<std::mutex> lock(global_lock);\n' % indent
-                    destroy_obj_code += '%s    DestroyObject(%s, %s, %s, pAllocator, %s, %s);\n' % (indent, cmd_info[0].name, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type), compatalloc_vuid, nullalloc_vuid)
-                    destroy_obj_code += '%s}\n' % indent
-        return object_array, destroy_obj_code
+                    validate_code += '%sskip |= ValidateDestroyObject(%s, %s, %s, pAllocator, %s, %s);\n' % (indent, cmd_info[0].name, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type), compatalloc_vuid, nullalloc_vuid)
+                    record_code += '%sRecordDestroyObject(%s, %s, %s);\n' % (indent, cmd_info[0].name, cmd_info[param].name, self.GetVulkanObjType(cmd_info[param].type))
+        return object_array, validate_code, record_code
     #
     # Output validation for a single object (obj_count is NULL) or a counted list of objects
-    def outputObjects(self, obj_type, obj_name, obj_count, prefix, index, indent, destroy_func, destroy_array, disp_name, parent_name, null_allowed, top_level):
-        decl_code = ''
+    def outputObjects(self, obj_type, obj_name, obj_count, prefix, index, indent, disp_name, parent_name, null_allowed, top_level):
         pre_call_code = ''
-        post_call_code = ''
         param_suffix = '%s-parameter' % (obj_name)
         parent_suffix = '%s-parent' % (obj_name)
         param_vuid = self.GetVuid(parent_name, param_suffix)
@@ -752,23 +747,18 @@
         if parent_vuid == 'kVUIDUndefined':
             parent_vuid = self.GetVuid(parent_name, 'commonparent')
         if obj_count is not None:
-            pre_call_code += '%s    for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, obj_count, index)
+            pre_call_code += '%sfor (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, obj_count, index)
             indent = self.incIndent(indent)
-            pre_call_code += '%s    skip |= ValidateObject(%s, %s%s[%s], %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, index, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
+            pre_call_code += '%sskip |= ValidateObject(%s, %s%s[%s], %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, index, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
             indent = self.decIndent(indent)
-            pre_call_code += '%s    }\n' % indent
+            pre_call_code += '%s}\n' % indent
         else:
-            pre_call_code += '%s    skip |= ValidateObject(%s, %s%s, %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
-        return decl_code, pre_call_code, post_call_code
+            pre_call_code += '%sskip |= ValidateObject(%s, %s%s, %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
+        return pre_call_code
     #
     # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
-    # create_func means that this is API creates or allocates objects
-    # destroy_func indicates that this API destroys or frees objects
-    # destroy_array means that the destroy_func operated on an array of objects
-    def validate_objects(self, members, indent, prefix, array_index, create_func, destroy_func, destroy_array, disp_name, parent_name, first_level_param):
-        decls = ''
+    def validate_objects(self, members, indent, prefix, array_index, disp_name, parent_name, first_level_param):
         pre_code = ''
-        post_code = ''
         index = 'index%s' % str(array_index)
         array_index += 1
         # Process any objects in this structure and recurse for any sub-structs in this struct
@@ -781,10 +771,8 @@
                 if (count_name is not None):
                     count_name = '%s%s' % (prefix, member.len)
                 null_allowed = member.isoptional
-                (tmp_decl, tmp_pre, tmp_post) = self.outputObjects(member.type, member.name, count_name, prefix, index, indent, destroy_func, destroy_array, disp_name, parent_name, str(null_allowed).lower(), first_level_param)
-                decls += tmp_decl
+                tmp_pre = self.outputObjects(member.type, member.name, count_name, prefix, index, indent, disp_name, parent_name, str(null_allowed).lower(), first_level_param)
                 pre_code += tmp_pre
-                post_code += tmp_post
             # Handle Structs that contain objects at some level
             elif member.type in self.struct_member_dict:
                 # Structs at first level will have an object
@@ -796,48 +784,43 @@
                     if member.len is not None:
                         # Update struct prefix
                         new_prefix = '%s%s' % (prefix, member.name)
-                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
+                        pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name)
                         indent = self.incIndent(indent)
-                        pre_code += '%s    for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index)
+                        pre_code += '%sfor (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index)
                         indent = self.incIndent(indent)
                         local_prefix = '%s[%s].' % (new_prefix, index)
                         # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.validate_objects(struct_info, indent, local_prefix, array_index, create_func, destroy_func, destroy_array, disp_name, member.type, False)
-                        decls += tmp_decl
+                        tmp_pre = self.validate_objects(struct_info, indent, local_prefix, array_index, disp_name, member.type, False)
                         pre_code += tmp_pre
-                        post_code += tmp_post
                         indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
+                        pre_code += '%s}\n' % indent
                         indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
+                        pre_code += '%s}\n' % indent
                     # Single Struct
                     elif ispointer:
                         # Update struct prefix
                         new_prefix = '%s%s->' % (prefix, member.name)
                         # Declare safe_VarType for struct
-                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
+                        pre_code += '%sif (%s%s) {\n' % (indent, prefix, member.name)
                         indent = self.incIndent(indent)
                         # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.validate_objects(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, disp_name, member.type, False)
-                        decls += tmp_decl
+                        tmp_pre = self.validate_objects(struct_info, indent, new_prefix, array_index, disp_name, member.type, False)
                         pre_code += tmp_pre
-                        post_code += tmp_post
                         indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
-                    else:
-                        # Update struct prefix
-                        new_prefix = '%s%s.' % (prefix, member.name)
-                        # Declare safe_VarType for struct
-                        # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.validate_objects(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, disp_name, member.type, False)
-                        decls += tmp_decl
-                        pre_code += tmp_pre
-                        post_code += tmp_post
-        return decls, pre_code, post_code
+                        pre_code += '%s}\n' % indent
+        return pre_code
     #
     # For a particular API, generate the object handling code
     def generate_wrapping_code(self, cmd):
         indent = '    '
+        pre_call_validate = ''
+        pre_call_record = ''
+        post_call_record = ''
+
+        destroy_array = False
+        validate_destroy_code = ''
+        record_destroy_code = ''
+
         proto = cmd.find('proto/name')
         params = cmd.findall('param')
         if proto.text is not None:
@@ -846,31 +829,16 @@
             disp_name = cmd_info[0].name
             # Handle object create operations if last parameter is created by this call
             if cmddata.iscreate:
-                create_obj_code = self.generate_create_object_code(indent, proto, params, cmd_info, cmddata.allocator)
-            else:
-                create_obj_code = ''
+                post_call_record += self.generate_create_object_code(indent, proto, params, cmd_info, cmddata.allocator)
             # Handle object destroy operations
             if cmddata.isdestroy:
-                (destroy_array, destroy_object_code) = self.generate_destroy_object_code(indent, proto, cmd_info)
-            else:
-                destroy_array = False
-                destroy_object_code = ''
-            paramdecl = ''
-            param_pre_code = ''
-            param_post_code = ''
-            create_func = True if create_obj_code else False
-            destroy_func = True if destroy_object_code else False
-            (paramdecl, param_pre_code, param_post_code) = self.validate_objects(cmd_info, indent, '', 0, create_func, destroy_func, destroy_array, disp_name, proto.text, True)
-            param_post_code += create_obj_code
-            if destroy_object_code:
-                if destroy_array == True:
-                    param_post_code += destroy_object_code
-                else:
-                    param_pre_code += destroy_object_code
-            if param_pre_code:
-                if (not destroy_func) or (destroy_array):
-                    param_pre_code = '%s{\n%s%s%s%s}\n' % ('    ', indent, self.lock_guard(indent), param_pre_code, indent)
-        return paramdecl, param_pre_code, param_post_code
+                (destroy_array, validate_destroy_code, record_destroy_code) = self.generate_destroy_object_code(indent, proto, cmd_info)
+
+            pre_call_record += record_destroy_code
+            pre_call_validate += self.validate_objects(cmd_info, indent, '', 0, disp_name, proto.text, True)
+            pre_call_validate += validate_destroy_code
+
+        return pre_call_validate, pre_call_record, post_call_record
     #
     # Capture command parameter info needed to create, destroy, and validate objects
     def genCmd(self, cmdinfo, cmdname, alias):
@@ -939,74 +907,89 @@
             cmdinfo = cmddata.cmdinfo
             if cmdname in self.interface_functions:
                 continue
+            manual = False
             if cmdname in self.no_autogen_list:
-                decls = self.makeCDecls(cmdinfo.elem)
-                self.appendSection('command', '')
-                self.appendSection('command', '// Declare only')
-                self.appendSection('command', decls[0])
-                self.intercepts += [ '    {"%s", (void *)%s},' % (cmdname,cmdname[2:]) ]
-                continue
+                manual = True
+
             # Generate object handling code
-            (api_decls, api_pre, api_post) = self.generate_wrapping_code(cmdinfo.elem)
-            # If API doesn't contain any object handles, don't fool with it
-            if not api_decls and not api_pre and not api_post:
-                continue
+            (pre_call_validate, pre_call_record, post_call_record) = self.generate_wrapping_code(cmdinfo.elem)
+
             feature_extra_protect = cmddata.extra_protect
-            if (feature_extra_protect != None):
+            if (feature_extra_protect is not None):
                 self.appendSection('command', '')
                 self.appendSection('command', '#ifdef '+ feature_extra_protect)
-                self.intercepts += [ '#ifdef %s' % feature_extra_protect ]
+                self.prototypes += [ '#ifdef %s' % feature_extra_protect ]
+
             # Add intercept to procmap
-            self.intercepts += [ '    {"%s", (void*)%s},' % (cmdname,cmdname[2:]) ]
+            self.prototypes += [ '    {"%s", (void*)%s},' % (cmdname,cmdname[2:]) ]
+
             decls = self.makeCDecls(cmdinfo.elem)
-            self.appendSection('command', '')
-            self.appendSection('command', decls[0][:-1])
-            self.appendSection('command', '{')
-            self.appendSection('command', '    bool skip = false;')
-            # Handle return values, if any
-            resulttype = cmdinfo.elem.find('proto/type')
-            if (resulttype != None and resulttype.text == 'void'):
-              resulttype = None
-            if (resulttype != None):
-                assignresult = resulttype.text + ' result = '
-            else:
-                assignresult = ''
-            # Pre-pend declarations and pre-api-call codegen
-            if api_decls:
-                self.appendSection('command', "\n".join(str(api_decls).rstrip().split("\n")))
-            if api_pre:
-                self.appendSection('command', "\n".join(str(api_pre).rstrip().split("\n")))
-            # Generate the API call itself
+
             # Gather the parameter items
             params = cmdinfo.elem.findall('param/name')
             # Pull out the text for each of the parameters, separate them by commas in a list
             paramstext = ', '.join([str(param.text) for param in params])
-            # Use correct dispatch table
-            disp_name = cmdinfo.elem.find('param/name').text
-            disp_type = cmdinfo.elem.find('param/type').text
-            if disp_type in ["VkInstance", "VkPhysicalDevice"] or cmdname == 'vkCreateInstance':
-                object_type = 'instance'
-            else:
-                object_type = 'device'
-            dispatch_table = 'GetLayerDataPtr(get_dispatch_key(%s), layer_data_map)->%s_dispatch_table.' % (disp_name, object_type)
-            API = cmdinfo.elem.attrib.get('name').replace('vk', dispatch_table, 1)
-            # Put all this together for the final down-chain call
-            if assignresult != '':
-                if resulttype.text == 'VkResult':
-                    self.appendSection('command', '    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;')
-                elif resulttype.text == 'VkBool32':
-                    self.appendSection('command', '    if (skip) return VK_FALSE;')
-                else:
-                    raise Exception('Unknown result type ' + resulttype.text)
-            else:
-                self.appendSection('command', '    if (skip) return;')
-            self.appendSection('command', '    ' + assignresult + API + '(' + paramstext + ');')
-            # And add the post-API-call codegen
-            self.appendSection('command', "\n".join(str(api_post).rstrip().split("\n")))
-            # Handle the return result variable, if any
-            if (resulttype != None):
-                self.appendSection('command', '    return result;')
-            self.appendSection('command', '}')
-            if (feature_extra_protect != None):
+            # Generate the API call template
+            fcn_call = cmdinfo.elem.attrib.get('name').replace('vk', 'TOKEN', 1) + '(' + paramstext + ');'
+
+            func_decl_template = decls[0][:-1].split('VKAPI_CALL ')
+            func_decl_template = func_decl_template[1]
+
+            result_type = cmdinfo.elem.find('proto/type')
+
+            if 'object_tracker.h' in self.genOpts.filename:
+                # Output PreCallValidateAPI prototype if necessary
+                if pre_call_validate:
+                    pre_cv_func_decl = 'bool PreCallValidate' + func_decl_template + ';'
+                    self.appendSection('command', pre_cv_func_decl)
+
+                # Output PreCallRecordAPI prototype if necessary
+                if pre_call_record:
+                    pre_cr_func_decl = 'void PreCallRecord' + func_decl_template + ';'
+                    self.appendSection('command', pre_cr_func_decl)
+
+                # Output PosCallRecordAPI prototype if necessary
+                if post_call_record:
+                    post_cr_func_decl = 'void PostCallRecord' + func_decl_template + ';'
+                    if result_type.text == 'VkResult':
+                        post_cr_func_decl = post_cr_func_decl.replace(')', ',\n    VkResult                                    result)')
+                    self.appendSection('command', post_cr_func_decl)
+
+            if 'object_tracker.cpp' in self.genOpts.filename:
+                # Output PreCallValidateAPI function if necessary
+                if pre_call_validate and not manual:
+                    pre_cv_func_decl = 'bool ObjectLifetimes::PreCallValidate' + func_decl_template + ' {'
+                    self.appendSection('command', '')
+                    self.appendSection('command', pre_cv_func_decl)
+                    self.appendSection('command', '    bool skip = false;')
+                    self.appendSection('command', pre_call_validate)
+                    self.appendSection('command', '    return skip;')
+                    self.appendSection('command', '}')
+
+                # Output PreCallRecordAPI function if necessary
+                if pre_call_record and not manual:
+                    pre_cr_func_decl = 'void ObjectLifetimes::PreCallRecord' + func_decl_template + ' {'
+                    self.appendSection('command', '')
+                    self.appendSection('command', pre_cr_func_decl)
+                    self.appendSection('command', pre_call_record)
+                    self.appendSection('command', '}')
+
+                # Output PosCallRecordAPI function if necessary
+                if post_call_record and not manual:
+                    post_cr_func_decl = 'void ObjectLifetimes::PostCallRecord' + func_decl_template + ' {'
+                    self.appendSection('command', '')
+
+                    if result_type.text == 'VkResult':
+                        post_cr_func_decl = post_cr_func_decl.replace(')', ',\n    VkResult                                    result)')
+                        # The two createpipelines APIs may create on failure -- skip the success result check
+                        if 'CreateGraphicsPipelines' not in cmdname and 'CreateComputePipelines' not in cmdname and 'CreateRayTracingPipelines' not in cmdname:
+                            post_cr_func_decl = post_cr_func_decl.replace('{', '{\n    if (result != VK_SUCCESS) return;')
+                    self.appendSection('command', post_cr_func_decl)
+
+
+                    self.appendSection('command', post_call_record)
+                    self.appendSection('command', '}')
+
+            if (feature_extra_protect is not None):
                 self.appendSection('command', '#endif // '+ feature_extra_protect)
-                self.intercepts += [ '#endif' ]
+                self.prototypes += [ '#endif' ]
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index 214695c..e8f6dcc 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -1,9 +1,9 @@
 #!/usr/bin/python3 -i
 #
-# Copyright (c) 2015-2018 The Khronos Group Inc.
-# Copyright (c) 2015-2018 Valve Corporation
-# Copyright (c) 2015-2018 LunarG, Inc.
-# Copyright (c) 2015-2018 Google Inc.
+# Copyright (c) 2015-2019 The Khronos Group Inc.
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -123,8 +123,59 @@
                  diagFile = sys.stdout):
         OutputGenerator.__init__(self, errFile, warnFile, diagFile)
         self.INDENT_SPACES = 4
-        self.intercepts = []
         self.declarations = []
+
+        inline_custom_source_preamble = """
+"""
+
+        # These functions have additional, custom-written checks in the utils cpp file. CodeGen will automatically add a call
+        # to those functions of the form 'bool manual_PreCallValidateAPIName', where the 'vk' is dropped.
+        # see 'manual_PreCallValidateCreateGraphicsPipelines' as an example.
+        self.functions_with_manual_checks = [
+            'vkCreateInstance',
+            'vkCreateDevice',
+            'vkCreateQueryPool'
+            'vkCreateRenderPass',
+            'vkCreateRenderPass2KHR',
+            'vkCreateBuffer',
+            'vkCreateImage',
+            'vkCreateImageView',
+            'vkCreateGraphicsPipelines',
+            'vkCreateComputePipelines',
+            'vkCreateSampler',
+            'vkCreateDescriptorSetLayout',
+            'vkFreeDescriptorSets',
+            'vkUpdateDescriptorSets',
+            'vkCreateRenderPass',
+            'vkCreateRenderPass2KHR',
+            'vkBeginCommandBuffer',
+            'vkCmdSetViewport',
+            'vkCmdSetScissor',
+            'vkCmdSetLineWidth',
+            'vkCmdDraw',
+            'vkCmdDrawIndirect',
+            'vkCmdDrawIndexedIndirect',
+            'vkCmdCopyImage',
+            'vkCmdBlitImage',
+            'vkCmdCopyBufferToImage',
+            'vkCmdCopyImageToBuffer',
+            'vkCmdUpdateBuffer',
+            'vkCmdFillBuffer',
+            'vkCreateSwapchainKHR',
+            'vkQueuePresentKHR',
+            'vkCreateDescriptorPool',
+            'vkCmdDispatch',
+            'vkCmdDispatchIndirect',
+            'vkCmdDispatchBaseKHR',
+            'vkCmdSetExclusiveScissorNV',
+            'vkCmdSetViewportShadingRatePaletteNV',
+            'vkCmdSetCoarseSampleOrderNV',
+            'vkCmdDrawMeshTasksNV',
+            'vkCmdDrawMeshTasksIndirectNV',
+            'vkCmdDrawMeshTasksIndirectCountNV',
+            'vkAllocateMemory',
+            ]
+
         # Commands to ignore
         self.blacklist = [
             'vkGetInstanceProcAddr',
@@ -134,23 +185,8 @@
             'vkEnumerateInstanceExtensionProperties',
             'vkEnumerateDeviceLayerProperties',
             'vkEnumerateDeviceExtensionProperties',
-            'vkCmdDebugMarkerEndEXT',
             ]
-        self.validate_only = [
-            'vkCreateInstance',
-            'vkDestroyInstance',
-            'vkCreateDevice',
-            'vkDestroyDevice',
-            'vkCreateQueryPool',
-            'vkCreateDebugReportCallbackEXT',
-            'vkDestroyDebugReportCallbackEXT',
-            'vkCreateCommandPool',
-            'vkCreateRenderPass',
-            'vkCreateRenderPass2KHR',
-            'vkDestroyRenderPass',
-            'vkCreateDebugUtilsMessengerEXT',
-            'vkDestroyDebugUtilsMessengerEXT',
-            ]
+
         # Structure fields to ignore
         self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] }
         # Validation conditions for some special case struct members that are conditionally validated
@@ -167,8 +203,6 @@
         self.validatedStructs = dict()                    # Map of structs type names to generated validation code for that struct type
         self.enumRanges = dict()                          # Map of enum name to BEGIN/END range values
         self.enumValueLists = ''                          # String containing enumerated type map definitions
-        self.func_pointers = ''                           # String containing function pointers for manual PV functions
-        self.typedefs = ''                                # String containing function pointer typedefs
         self.flags = set()                                # Map of flags typenames
         self.flagBits = dict()                            # Map of flag bits typename to list of values
         self.newFlags = set()                             # Map of flags typenames /defined in the current feature/
@@ -180,9 +214,10 @@
         self.valid_vuids = set()                          # Set of all valid VUIDs
         self.vuid_dict = dict()                           # VUID dictionary (from JSON)
         self.alias_dict = dict()                          # Dict of cmd|struct aliases
+        self.header_file = False                          # Header file generation flag
+        self.source_file = False                          # Source file generation flag
         self.returnedonly_structs = []
         # Named tuples to store struct and command data
-        self.StructType = namedtuple('StructType', ['name', 'value'])
         self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum',
                                                         'isconst', 'isoptional', 'iscount', 'noautovalidity',
                                                         'len', 'extstructs', 'condition', 'cdecl'])
@@ -247,6 +282,29 @@
     # Called at file creation time
     def beginFile(self, genOpts):
         OutputGenerator.beginFile(self, genOpts)
+        self.header_file = (genOpts.filename == 'parameter_validation.h')
+        self.source_file = (genOpts.filename == 'parameter_validation.cpp')
+
+        if not self.header_file and not self.source_file:
+            print("Error: Output Filenames have changed, update generator source.\n")
+            sys.exit(1)
+
+        if self.source_file or self.header_file:
+            # Output Copyright text
+            s = self.GenerateCopyright()
+            write(s, file=self.outFile)
+
+        if self.header_file:
+            return
+
+        # Build map of structure type names to VkStructureType enum values
+        # Find all types of category "struct"
+        for struct in self.registry.tree.iterfind('types/type[@category="struct"]'):
+            # Check if struct has member named "sType" of type "VkStructureType" which has values defined
+            stype = struct.find('member[name="sType"][type="VkStructureType"][@values]')
+            if stype is not None:
+                # Store VkStructureType value for this type
+                self.structTypes[struct.get('name')] = stype.get('values')
 
         self.valid_usage_path = genOpts.valid_usage_path
         vu_json_filename = os.path.join(self.valid_usage_path + os.sep, 'validusage.json')
@@ -257,115 +315,77 @@
         if len(self.vuid_dict) == 0:
             print("Error: Could not find, or error loading %s/validusage.json\n", vu_json_filename)
             sys.exit(1)
-
-        # C-specific
         #
         # Build a set of all vuid text strings found in validusage.json
         for json_vuid_string in self.ExtractVUIDs(self.vuid_dict):
             self.valid_vuids.add(json_vuid_string)
         #
-        # User-supplied prefix text, if any (list of strings)
-        s = self.GenerateCopyright()
-        write(s, file=self.outFile)
-        #
         # Headers
-        write('#include <string>', file=self.outFile)
+        write('#include "chassis.h"', file=self.outFile)
         self.newline()
-        write('#include "vk_loader_platform.h"', file=self.outFile)
-        write('#include "vulkan/vulkan.h"', file=self.outFile)
-        write('#include "vk_layer_extension_utils.h"', file=self.outFile)
-        write('#include "parameter_validation.h"', file=self.outFile)
-        #
-        # Macros
+        write('#include "stateless_validation.h"', file=self.outFile)
         self.newline()
-        write('#ifndef UNUSED_PARAMETER', file=self.outFile)
-        write('#define UNUSED_PARAMETER(x) (void)(x)', file=self.outFile)
-        write('#endif // UNUSED_PARAMETER', file=self.outFile)
-        #
-        # Namespace
-        self.newline()
-        write('namespace parameter_validation {', file = self.outFile)
-        self.newline()
-        write('extern std::mutex global_lock;', file = self.outFile)
-        write('extern std::unordered_map<void *, layer_data *> layer_data_map;', file = self.outFile)
-        write('extern std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;', file = self.outFile)
-        self.newline()
-        #
-        # FuncPtrMap
-        self.func_pointers += 'std::unordered_map<std::string, void *> custom_functions = {\n'
     #
     # Called at end-time for final content output
     def endFile(self):
-        # C-specific
-        self.newline()
-        write(self.enumValueLists, file=self.outFile)
-        self.newline()
-        write(self.typedefs, file=self.outFile)
-        self.newline()
-        self.func_pointers += '};\n'
-        write(self.func_pointers, file=self.outFile)
-        self.newline()
+        if self.source_file:
+            # C-specific
+            self.newline()
+            write(self.enumValueLists, file=self.outFile)
+            self.newline()
 
-        pnext_handler  = 'bool ValidatePnextStructContents(debug_report_data *report_data, const char *api_name, const ParameterName &parameter_name, const GenericHeader* header) {\n'
-        pnext_handler += '    bool skip = false;\n'
-        pnext_handler += '    switch(header->sType) {\n'
+            pnext_handler  = 'bool StatelessValidation::ValidatePnextStructContents(const char *api_name, const ParameterName &parameter_name, const GenericHeader* header) {\n'
+            pnext_handler += '    bool skip = false;\n'
+            pnext_handler += '    switch(header->sType) {\n'
 
-        # Do some processing here to extract data from validatedstructs...
-        for item in self.structextends_list:
-            postProcSpec = {}
-            postProcSpec['ppp'] = '' if not item else '{postProcPrefix}'
-            postProcSpec['pps'] = '' if not item else '{postProcSuffix}'
-            postProcSpec['ppi'] = '' if not item else '{postProcInsert}'
+            # Do some processing here to extract data from validatedstructs...
+            for item in self.structextends_list:
+                postProcSpec = {}
+                postProcSpec['ppp'] = '' if not item else '{postProcPrefix}'
+                postProcSpec['pps'] = '' if not item else '{postProcSuffix}'
+                postProcSpec['ppi'] = '' if not item else '{postProcInsert}'
 
-            pnext_case = '\n'
-            protect = ''
-            # Guard struct cases with feature ifdefs, if necessary
-            if item in self.struct_feature_protect.keys():
-                protect = self.struct_feature_protect[item]
-                pnext_case += '#ifdef %s\n' % protect
-            pnext_case += '        // Validation code for %s structure members\n' % item
-            pnext_case += '        case %s: {\n' % self.getStructType(item)
-            pnext_case += '            %s *structure = (%s *) header;\n' % (item, item)
-            expr = self.expandStructCode(item, item, 'structure->', '', '            ', [], postProcSpec)
-            struct_validation_source = self.ScrubStructCode(expr)
-            pnext_case += '%s' % struct_validation_source
-            pnext_case += '        } break;\n'
-            if protect is not '':
-                pnext_case += '#endif // %s\n' % protect
-            # Skip functions containing no validation
-            if struct_validation_source != '':
-                pnext_handler += pnext_case;
-        pnext_handler += '        default:\n'
-        pnext_handler += '            skip = false;\n'
-        pnext_handler += '    }\n'
-        pnext_handler += '    return skip;\n'
-        pnext_handler += '}\n'
-        write(pnext_handler, file=self.outFile)
-        self.newline()
+                pnext_case = '\n'
+                protect = ''
+                # Guard struct cases with feature ifdefs, if necessary
+                if item in self.struct_feature_protect.keys():
+                    protect = self.struct_feature_protect[item]
+                    pnext_case += '#ifdef %s\n' % protect
+                pnext_case += '        // Validation code for %s structure members\n' % item
+                pnext_case += '        case %s: {\n' % self.structTypes[item]
+                pnext_case += '            %s *structure = (%s *) header;\n' % (item, item)
+                expr = self.expandStructCode(item, item, 'structure->', '', '            ', [], postProcSpec)
+                struct_validation_source = self.ScrubStructCode(expr)
+                pnext_case += '%s' % struct_validation_source
+                pnext_case += '        } break;\n'
+                if protect is not '':
+                    pnext_case += '#endif // %s\n' % protect
+                # Skip functions containing no validation
+                if struct_validation_source != '':
+                    pnext_handler += pnext_case;
+            pnext_handler += '        default:\n'
+            pnext_handler += '            skip = false;\n'
+            pnext_handler += '    }\n'
+            pnext_handler += '    return skip;\n'
+            pnext_handler += '}\n'
+            write(pnext_handler, file=self.outFile)
+            self.newline()
 
-        ext_template  = 'template <typename T>\n'
-        ext_template += 'bool OutputExtensionError(const T *layer_data, const std::string &api_name, const std::string &extension_name) {\n'
-        ext_template += '    return log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,\n'
-        ext_template += '                   kVUID_PVError_ExtensionNotEnabled, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n'
-        ext_template += '                   api_name.c_str(), extension_name.c_str());\n'
-        ext_template += '}\n'
-        write(ext_template, file=self.outFile)
-        self.newline()
-        commands_text = '\n'.join(self.validation)
-        write(commands_text, file=self.outFile)
-        self.newline()
-        # Output declarations and record intercepted procedures
-        write('// Declarations', file=self.outFile)
-        write('\n'.join(self.declarations), file=self.outFile)
-        write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
-        write('\n'.join(self.intercepts), file=self.outFile)
-        write('};\n', file=self.outFile)
-        self.newline()
-        # Namespace
-        write('} // namespace parameter_validation', file = self.outFile)
-        # Finish processing in superclass
-        OutputGenerator.endFile(self)
+            ext_template  = 'bool StatelessValidation::OutputExtensionError(const std::string &api_name, const std::string &extension_name) {\n'
+            ext_template += '    return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,\n'
+            ext_template += '                   kVUID_PVError_ExtensionNotEnabled, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n'
+            ext_template += '                   api_name.c_str(), extension_name.c_str());\n'
+            ext_template += '}\n'
+            write(ext_template, file=self.outFile)
+            self.newline()
+            commands_text = '\n'.join(self.validation)
+            write(commands_text, file=self.outFile)
+            self.newline()
+        if self.header_file:
+            # Output declarations and record intercepted procedures
+            write('\n'.join(self.declarations), file=self.outFile)
+            # Finish processing in superclass
+            OutputGenerator.endFile(self)
     #
     # Processing at beginning of each feature or extension
     def beginFeature(self, interface, emit):
@@ -411,13 +431,15 @@
     #
     # Called at the end of each extension (feature)
     def endFeature(self):
+        if self.header_file:
+            return
         # C-specific
         # Actually write the interface to the output file.
         if (self.emit):
             # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
             # or move it below the 'for section...' loop.
             ifdef = ''
-            if (self.featureExtraProtect != None):
+            if (self.featureExtraProtect is not None):
                 ifdef = '#ifdef %s\n' % self.featureExtraProtect
                 self.validation.append(ifdef)
             # Generate the struct member checking code from the captured data
@@ -426,7 +448,7 @@
             self.processCmdData()
             # Write the declaration for the HeaderVersion
             if self.headerVersion:
-                write('const uint32_t GeneratedHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
+                write('const uint32_t GeneratedVulkanHeaderVersion = {};'.format(self.headerVersion), file=self.outFile)
                 self.newline()
             # Write the declarations for the VkFlags values combining all flag bits
             for flag in sorted(self.newFlags):
@@ -439,7 +461,7 @@
                     decl += ';'
                     write(decl, file=self.outFile)
             endif = '\n'
-            if (self.featureExtraProtect != None):
+            if (self.featureExtraProtect is not None):
                 endif = '#endif // %s\n' % self.featureExtraProtect
             self.validation.append(endif)
         # Finish processing in superclass
@@ -448,7 +470,7 @@
     # Type generation
     def genType(self, typeinfo, name, alias):
         # record the name/alias pair
-        if alias != None:
+        if alias is not None:
             self.alias_dict[name]=alias
         OutputGenerator.genType(self, typeinfo, name, alias)
         typeElem = typeinfo.elem
@@ -471,6 +493,8 @@
     # type declarations. The <member> tags are just like <param> tags - they are a declaration of a struct or union member.
     # Only simple member declarations are supported (no nested structs etc.)
     def genStruct(self, typeinfo, typeName, alias):
+        if not self.source_file:
+            return
         # alias has already been recorded in genType, above
         OutputGenerator.genStruct(self, typeinfo, typeName, alias)
         conditions = self.structMemberValidationConditions[typeName] if typeName in self.structMemberValidationConditions else None
@@ -494,19 +518,7 @@
             name = info[1]
             stypeValue = ''
             cdecl = self.makeCParamDecl(member, 0)
-            # Process VkStructureType
-            if type == 'VkStructureType':
-                # Extract the required struct type value from the comments embedded in the original text defining the
-                # 'typeinfo' element
-                rawXml = etree.tostring(typeinfo.elem).decode('ascii')
-                result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
-                if result:
-                    value = result.group(0)
-                else:
-                    value = self.genVkStructureType(typeName)
-                # Store the required type value
-                self.structTypes[typeName] = self.StructType(name=name, value=value)
-            #
+
             # Store pointer/array/string info -- Check for parameter name in lens set
             iscount = False
             if name in lens:
@@ -548,8 +560,10 @@
     # Capture group (e.g. C "enum" type) info to be used for param check code generation.
     # These are concatenated together with other types.
     def genGroup(self, groupinfo, groupName, alias):
+        if not self.source_file:
+            return
         # record the name/alias pair
-        if alias != None:
+        if alias is not None:
             self.alias_dict[groupName]=alias
         OutputGenerator.genGroup(self, groupinfo, groupName, alias)
         groupElem = groupinfo.elem
@@ -589,67 +603,57 @@
     # Capture command parameter info to be used for param check code generation.
     def genCmd(self, cmdinfo, name, alias):
         # record the name/alias pair
-        if alias != None:
+        if alias is not None:
             self.alias_dict[name]=alias
         OutputGenerator.genCmd(self, cmdinfo, name, alias)
         decls = self.makeCDecls(cmdinfo.elem)
         typedef = decls[1]
         typedef = typedef.split(')',1)[1]
-        if name not in self.blacklist:
-            if (self.featureExtraProtect != None):
-                self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
-                self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
-                if (name not in self.validate_only):
-                    self.func_pointers += '#ifdef %s\n' % self.featureExtraProtect
-                    self.typedefs += '#ifdef %s\n' % self.featureExtraProtect
-            if (name not in self.validate_only):
-                self.typedefs += 'typedef bool (*PFN_manual_%s)%s\n' % (name, typedef)
-                self.func_pointers += '    {"%s", nullptr},\n' % name
-            self.intercepts += [ '    {"%s", (void*)%s},' % (name,name) ]
-            # Strip off 'vk' from API name
-            self.declarations += [ '%s' % decls[0].replace("VKAPI_CALL vk", "VKAPI_CALL ") ]
-            if (self.featureExtraProtect != None):
-                self.intercepts += [ '#endif' ]
-                self.declarations += [ '#endif' ]
-                if (name not in self.validate_only):
-                    self.func_pointers += '#endif\n'
-                    self.typedefs += '#endif\n'
-        if name not in self.blacklist:
-            params = cmdinfo.elem.findall('param')
-            # Get list of array lengths
-            lens = set()
-            for param in params:
-                len = self.getLen(param)
-                if len:
-                    lens.add(len)
-            # Get param info
-            paramsInfo = []
-            for param in params:
-                paramInfo = self.getTypeNameTuple(param)
-                cdecl = self.makeCParamDecl(param, 0)
-                # Check for parameter name in lens set
-                iscount = False
-                if paramInfo[1] in lens:
-                    iscount = True
-                paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
-                                                    ispointer=self.paramIsPointer(param),
-                                                    isstaticarray=self.paramIsStaticArray(param),
-                                                    isbool=True if paramInfo[0] == 'VkBool32' else False,
-                                                    israngedenum=True if paramInfo[0] in self.enumRanges else False,
-                                                    isconst=True if 'const' in cdecl else False,
-                                                    isoptional=self.paramIsOptional(param),
-                                                    iscount=iscount,
-                                                    noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
-                                                    len=self.getLen(param),
-                                                    extstructs=None,
-                                                    condition=None,
-                                                    cdecl=cdecl))
-            # Save return value information, if any
-            result_type = ''
-            resultinfo = cmdinfo.elem.find('proto/type')
-            if (resultinfo != None and resultinfo.text != 'void'):
-                result_type = resultinfo.text
-            self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type))
+        if self.header_file:
+            if name not in self.blacklist:
+                if (self.featureExtraProtect is not None):
+                    self.declarations += [ '#ifdef %s' % self.featureExtraProtect ]
+                # Strip off 'vk' from API name
+                self.declarations += [ '%s%s' % ('bool PreCallValidate', decls[0].split("VKAPI_CALL vk")[1])]
+                if (self.featureExtraProtect is not None):
+                    self.declarations += [ '#endif' ]
+        if self.source_file:
+            if name not in self.blacklist:
+                params = cmdinfo.elem.findall('param')
+                # Get list of array lengths
+                lens = set()
+                for param in params:
+                    len = self.getLen(param)
+                    if len:
+                        lens.add(len)
+                # Get param info
+                paramsInfo = []
+                for param in params:
+                    paramInfo = self.getTypeNameTuple(param)
+                    cdecl = self.makeCParamDecl(param, 0)
+                    # Check for parameter name in lens set
+                    iscount = False
+                    if paramInfo[1] in lens:
+                        iscount = True
+                    paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1],
+                                                        ispointer=self.paramIsPointer(param),
+                                                        isstaticarray=self.paramIsStaticArray(param),
+                                                        isbool=True if paramInfo[0] == 'VkBool32' else False,
+                                                        israngedenum=True if paramInfo[0] in self.enumRanges else False,
+                                                        isconst=True if 'const' in cdecl else False,
+                                                        isoptional=self.paramIsOptional(param),
+                                                        iscount=iscount,
+                                                        noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
+                                                        len=self.getLen(param),
+                                                        extstructs=None,
+                                                        condition=None,
+                                                        cdecl=cdecl))
+                # Save return value information, if any
+                result_type = ''
+                resultinfo = cmdinfo.elem.find('proto/type')
+                if (resultinfo is not None and resultinfo.text != 'void'):
+                    result_type = resultinfo.text
+                self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type))
     #
     # Check if the parameter passed in is a pointer
     def paramIsPointer(self, param):
@@ -707,36 +711,6 @@
             return True
         return False
     #
-    # Generate a VkStructureType based on a structure typename
-    def genVkStructureType(self, typename):
-        # Add underscore between lowercase then uppercase
-        value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
-        value = value.replace('ASTCDecode', 'ASTC_Decode')
-        value = value.replace('D3_D12', 'D3D12')
-        value = value.replace('Device_IDProp', 'Device_ID_Prop')
-        value = value.replace('e8_Bit', 'E_8BIT')
-        value = value.replace('e16_Bit', 'E_16BIT')
-        value = value.replace('Features2', 'FEATURES_2')
-        value = value.replace('LODGather', 'LOD_Gather')
-        value = value.replace('PCIBus', 'PCI_Bus')
-        # Change to uppercase
-        value = value.upper()
-        # Add STRUCTURE_TYPE_
-        return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
-    #
-    # Get the cached VkStructureType value for the specified struct typename, or generate a VkStructureType
-    # value assuming the struct is defined by a different feature
-    # TODO: The structTypes list gets built incrementally -- half the time, the sType you're looking for is not yet in the list.
-    #       The list needs to be built up-front, probably by accessing the XML directly, or by rewriting the generator.
-    def getStructType(self, typename):
-        value = None
-        if typename in self.structTypes:
-            value = self.structTypes[typename].value
-        else:
-            value = self.genVkStructureType(typename)
-            self.logMsg('diag', 'ParameterValidation: Generating {} for {} structure type that was not defined by the current feature'.format(value, typename))
-        return value
-    #
     # Retrieve the value of the len tag
     def getLen(self, param):
         result = None
@@ -860,7 +834,7 @@
             if name in self.alias_dict:
                 alias_string = 'VUID-%s-%s' % (self.alias_dict[name], suffix)
                 if alias_string in self.valid_vuids:
-                    vuid = "\"%s\"" % vuid_string
+                    vuid = "\"%s\"" % alias_string
         return vuid
     #
     # Generate the sType check string
@@ -872,19 +846,21 @@
         param_vuid = self.GetVuid(vuid_name, "%s-parameter" % value.name)
 
         if lenValue:
+            count_required_vuid = self.GetVuid(vuid_name, "%s-arraylength" % lenValue.name)
+
             # This is an array with a pointer to a count value
             if lenValue.ispointer:
                 # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
-                checkExpr.append('skip |= validate_struct_type_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {});\n'.format(
-                    funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, stype_vuid, param_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
+                checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {}, {});\n'.format(
+                    funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, stype_vuid, param_vuid, count_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec))
             # This is an array with an integer count value
             else:
-                checkExpr.append('skip |= validate_struct_type_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {});\n'.format(
-                    funcPrintName, lenValueRequired, valueRequired, stype_vuid, param_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix, **postProcSpec))
+                checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {});\n'.format(
+                    funcPrintName, lenValueRequired, valueRequired, stype_vuid, param_vuid, count_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec))
         # This is an individual struct
         else:
-            checkExpr.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {}, {});\n'.format(
-                funcPrintName, valuePrintName, prefix, valueRequired, param_vuid, stype_vuid, vn=value.name, sv=stype.value, vt=value.type, **postProcSpec))
+            checkExpr.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {}, {});\n'.format(
+                funcPrintName, valuePrintName, prefix, valueRequired, param_vuid, stype_vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec))
         return checkExpr
     #
     # Generate the handle check string
@@ -896,7 +872,7 @@
                 raise('Unsupported parameter validation case: Output handle array elements are not NULL checked')
             else:
                 # This is an array with an integer count value
-                checkExpr.append('skip |= validate_handle_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
+                checkExpr.append('skip |= validate_handle_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
                     funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
         else:
             # This is assumed to be an output handle pointer
@@ -911,7 +887,7 @@
             raise('Unsupported parameter validation case: array of reserved VkFlags')
         else:
             allFlags = 'All' + flagBitsName
-            checkExpr.append('skip |= validate_flags_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec))
+            checkExpr.append('skip |= validate_flags_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec))
         return checkExpr
     #
     # Generate pNext check string
@@ -926,8 +902,8 @@
             extStructVar = 'allowed_structs_{}'.format(struct_type_name)
             extStructCount = 'ARRAY_SIZE({})'.format(extStructVar)
             extStructNames = '"' + ', '.join(value.extstructs) + '"'
-            checkExpr.append('const VkStructureType {}[] = {{ {} }};\n'.format(extStructVar, ', '.join([self.getStructType(s) for s in value.extstructs])))
-        checkExpr.append('skip |= validate_struct_pnext(local_data->report_data, "{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedHeaderVersion, {});\n'.format(
+            checkExpr.append('const VkStructureType {}[] = {{ {} }};\n'.format(extStructVar, ', '.join([self.structTypes[s] for s in value.extstructs])))
+        checkExpr.append('skip |= validate_struct_pnext("{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedVulkanHeaderVersion, {});\n'.format(
             funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar, vuid, **postProcSpec))
         return checkExpr
     #
@@ -943,18 +919,18 @@
                 # If count and array parameters are optional, there will be no validation
                 if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true':
                     # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
-                    checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format(
+                    checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format(
                         funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
             # This is an array with an integer count value
             else:
                 # If count and array parameters are optional, there will be no validation
                 if valueRequired == 'true' or lenValueRequired == 'true':
                     if value.type != 'char':
-                        checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format(
+                        checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format(
                             funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
                     else:
                         # Arrays of strings receive special processing
-                        checkExpr.append('skip |= validate_string_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
+                        checkExpr.append('skip |= validate_string_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
                             funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
             if checkExpr:
                 if lenValue and ('->' in lenValue.name):
@@ -973,9 +949,9 @@
                 vuid = allocator_dict.get(value.name)
                 if vuid is not None:
                     ptr_required_vuid = vuid
-                checkExpr.append('skip |= validate_required_pointer(local_data->report_data, "{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
+                checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
             else:
-                checkExpr.append('skip |= validate_required_pointer(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
+                checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec))
         return checkExpr
     #
     # Process struct member validation code, performing name substitution if required
@@ -1153,11 +1129,11 @@
                     elif value.type in self.flags and value.isconst:
                         usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec)
                     elif value.isbool and value.isconst:
-                        usedLines.append('skip |= validate_bool32_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
+                        usedLines.append('skip |= validate_bool32_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
                     elif value.israngedenum and value.isconst:
                         enum_value_list = 'All%sEnums' % value.type
-                        usedLines.append('skip |= validate_ranged_enum_array(local_data->report_data, "{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enum_value_list, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
-                    elif value.name == 'pNext':
+                        usedLines.append('skip |= validate_ranged_enum_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enum_value_list, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec))
+                    elif value.name == 'pNext' and value.isconst:
                         usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName, postProcSpec, structTypeName)
                     else:
                         usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec, structTypeName)
@@ -1181,16 +1157,16 @@
                         stype = self.structTypes[value.type]
                         vuid = self.GetVuid(value.type, "sType-sType")
                         undefined_vuid = '"kVUIDUndefined"'
-                        usedLines.append('skip |= validate_struct_type(local_data->report_data, "{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, kVUIDUndefined, {});\n'.format(
-                            funcName, valueDisplayName, valuePrefix, vuid, vn=value.name, sv=stype.value, vt=value.type, **postProcSpec))
+                        usedLines.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, kVUIDUndefined, {});\n'.format(
+                            funcName, valueDisplayName, valuePrefix, vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec))
                     elif value.type in self.handleTypes:
                         if not self.isHandleOptional(value, None):
-                            usedLines.append('skip |= validate_required_handle(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
+                            usedLines.append('skip |= validate_required_handle("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
                     elif value.type in self.flags:
                         flagBitsName = value.type.replace('Flags', 'FlagBits')
                         if not flagBitsName in self.flagBits:
                             vuid = self.GetVuid(vuid_name_tag, "%s-zerobitmask" % (value.name))
-                            usedLines.append('skip |= validate_reserved_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec))
+                            usedLines.append('skip |= validate_reserved_flags("{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec))
                         else:
                             if value.isoptional:
                                 flagsRequired = 'false'
@@ -1199,18 +1175,18 @@
                                 flagsRequired = 'true'
                                 vuid = self.GetVuid(vuid_name_tag, "%s-requiredbitmask" % (value.name))
                             allFlagsName = 'All' + flagBitsName
-                            usedLines.append('skip |= validate_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, false, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
+                            usedLines.append('skip |= validate_flags("{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, false, {});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
                     elif value.type in self.flagBits:
                         flagsRequired = 'false' if value.isoptional else 'true'
                         allFlagsName = 'All' + value.type
                         vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name))
-                        usedLines.append('skip |= validate_flags(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, true, {});\n'.format(funcName, valueDisplayName, value.type, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
+                        usedLines.append('skip |= validate_flags("{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, true, {});\n'.format(funcName, valueDisplayName, value.type, allFlagsName, value.name, flagsRequired, vuid, pf=valuePrefix, **postProcSpec))
                     elif value.isbool:
-                        usedLines.append('skip |= validate_bool32(local_data->report_data, "{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
+                        usedLines.append('skip |= validate_bool32("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec))
                     elif value.israngedenum:
                         vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name))
                         enum_value_list = 'All%sEnums' % value.type
-                        usedLines.append('skip |= validate_ranged_enum(local_data->report_data, "{}", {ppp}"{}"{pps}, "{}", {}, {}{}, {});\n'.format(funcName, valueDisplayName, value.type, enum_value_list, valuePrefix, value.name, vuid, **postProcSpec))
+                        usedLines.append('skip |= validate_ranged_enum("{}", {ppp}"{}"{pps}, "{}", {}, {}{}, {});\n'.format(funcName, valueDisplayName, value.type, enum_value_list, valuePrefix, value.name, vuid, **postProcSpec))
                     # If this is a struct, see if it contains members that need to be checked
                     if value.type in self.validatedStructs:
                         memberNamePrefix = '{}{}.'.format(valuePrefix, value.name)
@@ -1244,15 +1220,16 @@
     def processCmdData(self):
         indent = self.incIndent(None)
         for command in self.commands:
-            just_validate = False
-            if command.name in self.validate_only:
-                just_validate = True
             # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance)
             startIndex = 0 if command.name == 'vkCreateInstance' else 1
             lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None)
             # Cannot validate extension dependencies for device extension APIs having a physical device as their dispatchable object
             if (command.name in self.required_extensions) and (self.extension_type != 'device' or command.params[0].type != 'VkPhysicalDevice'):
                 ext_test = ''
+                if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'vkCreateInstance':
+                    ext_table_type = 'instance'
+                else:
+                    ext_table_type = 'device'
                 for ext in self.required_extensions[command.name]:
                     ext_name_define = ''
                     ext_enable_name = ''
@@ -1262,77 +1239,27 @@
                             ext_enable_name = ext_name_define.lower()
                             ext_enable_name = re.sub('_extension_name', '', ext_enable_name)
                             break
-                    ext_test = 'if (!local_data->extensions.%s) skip |= OutputExtensionError(local_data, "%s", %s);\n' % (ext_enable_name, command.name, ext_name_define)
+                    ext_test = 'if (!%s_extensions.%s) skip |= OutputExtensionError("%s", %s);\n' % (ext_table_type, ext_enable_name, command.name, ext_name_define)
                     lines.insert(0, ext_test)
             if lines:
-                cmdDef = self.getCmdDef(command) + '\n'
-                # For a validation-only routine, change the function declaration
-                if just_validate:
-                    jv_def = '// Generated function handles validation only -- API definition is in non-generated source\n'
-                    jv_def += 'extern %s\n\n' % command.cdecl
-                    cmdDef = 'bool parameter_validation_' + cmdDef.split('VKAPI_CALL ',1)[1]
-                    if command.name == 'vkCreateInstance':
-                        cmdDef = cmdDef.replace('(\n', '(\n    VkInstance instance,\n')
-                    cmdDef = jv_def + cmdDef
-                cmdDef += '{\n'
-
-                # Add list of commands to skip -- just generate the routine signature and put the manual source in parameter_validation_utils.cpp
-                if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'vkCreateInstance':
-                    map_name = 'instance_layer_data_map'
-                    map_type = 'instance_layer_data'
-                else:
-                    map_name = 'layer_data_map'
-                    map_type = 'layer_data'
-                instance_param = command.params[0].name
-                if command.name == 'vkCreateInstance':
-                    instance_param = 'instance'
-                layer_data = '    %s *local_data = GetLayerDataPtr(get_dispatch_key(%s), %s);\n' % (map_type, instance_param, map_name)
-                cmdDef += layer_data
+                func_sig = self.getCmdDef(command) + ' {\n'
+                func_sig = func_sig.split('VKAPI_CALL vk')[1]
+                cmdDef = 'bool StatelessValidation::PreCallValidate' + func_sig
                 cmdDef += '%sbool skip = false;\n' % indent
-                if not just_validate:
-                    if command.result != '':
-                        if command.result == "VkResult":
-                            cmdDef += indent + '%s result = VK_ERROR_VALIDATION_FAILED_EXT;\n' % command.result
-                        elif command.result == "VkBool32":
-                            cmdDef += indent + '%s result = VK_FALSE;\n' % command.result
-                        else:
-                            raise Exception("Unknown result type: " + command.result)
-
-                    cmdDef += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % indent
+                # Insert call to custom-written function if present
+                if command.name in self.functions_with_manual_checks:
+                    # Generate parameter list for manual fcn and down-chain calls
+                    params_text = ''
+                    for param in command.params:
+                        params_text += '%s, ' % param.name
+                    params_text = params_text[:-2] + ');\n'
+                    cmdDef += '    skip |= manual_PreCallValidate'+ command.name[2:] + '(' + params_text
                 for line in lines:
-                    cmdDef += '\n'
                     if type(line) is list:
                         for sub in line:
                             cmdDef += indent + sub
                     else:
                         cmdDef += indent + line
-                cmdDef += '\n'
-                if not just_validate:
-                    # Generate parameter list for manual fcn and down-chain calls
-                    params_text = ''
-                    for param in command.params:
-                        params_text += '%s, ' % param.name
-                    params_text = params_text[:-2]
-                    # Generate call to manual function if its function pointer is non-null
-                    cmdDef += '%sPFN_manual_%s custom_func = (PFN_manual_%s)custom_functions["%s"];\n' % (indent, command.name, command.name, command.name)
-                    cmdDef += '%sif (custom_func != nullptr) {\n' % indent
-                    cmdDef += '    %sskip |= custom_func(%s);\n' % (indent, params_text)
-                    cmdDef += '%s}\n\n' % indent
-                    # Release the validation lock
-                    cmdDef += '%slock.unlock();\n' % indent
-                    # Generate skip check and down-chain call
-                    cmdDef += '%sif (!skip) {\n'  % indent
-                    down_chain_call = '    %s' % indent
-                    if command.result != '':
-                        down_chain_call += '    result = '
-                    # Generate down-chain API call
-                    api_call = '%s(%s);' % (command.name, params_text)
-                    down_chain_call += 'local_data->dispatch_table.%s\n' % api_call[2:]
-                    cmdDef += down_chain_call
-                    cmdDef += '%s}\n' % indent
-                    if command.result != '':
-                        cmdDef += '%sreturn result;\n' % indent
-                else:
-                    cmdDef += '%sreturn skip;\n' % indent
+                cmdDef += '%sreturn skip;\n' % indent
                 cmdDef += '}\n'
                 self.validation.append(cmdDef)
diff --git a/scripts/parse_test_results.py b/scripts/parse_test_results.py
index ce428c5..6571d8c 100644
--- a/scripts/parse_test_results.py
+++ b/scripts/parse_test_results.py
@@ -109,18 +109,18 @@
         return did_fail
 
     def new_profile_match(self, line):
-        if re.search(r'Testing with profile .*/(.*)', line) != None:
+        if re.search(r'Testing with profile .*/(.*)', line) is not None:
             self.current_profile = re.search(r'Testing with profile .*/(.*)', line).group(1)
 
     def test_suite_end_match(self, line):
-        if re.search(r'\[-*\]', line) != None:
+        if re.search(r'\[-*\]', line) is not None:
             if self.current_test != "":
                 # Here we see a message that starts [----------] before another test
                 # finished running. This should mean that that other test died.
                 self.test_died()
 
     def start_test_match(self, line):
-        if re.search(r'\[ RUN\s*\]', line) != None:
+        if re.search(r'\[ RUN\s*\]', line) is not None:
             # This parser doesn't handle the case where one test's start comes between another
             # test's start and result.
             assert self.current_test == ""
@@ -128,23 +128,23 @@
             self.current_test_output = ""
 
     def skip_test_match(self, line):
-        if re.search(r'TEST SKIPPED', line) != None:
+        if re.search(r'TEST SKIPPED', line) is not None:
             self.test_results[self.current_test][self.current_profile] = "skip"
 
     def pass_test_match(self, line):
-        if re.search(r'\[\s*OK \]', line) != None:
+        if re.search(r'\[\s*OK \]', line) is not None:
             # If gtest says the test passed, check if it was skipped before marking it passed
             if self.test_results.get(self.current_test, {}).get(self.current_profile, "") != "skip":
                     self.test_results[self.current_test][self.current_profile] = "pass"
             self.current_test = ""
 
     def fail_test_match(self, line):
-        if re.search(r'\[\s*FAILED\s*\]', line) != None and self.current_test != "":
+        if re.search(r'\[\s*FAILED\s*\]', line) is not None and self.current_test != "":
             self.test_results[self.current_test][self.current_profile] = "fail"
             self.current_test = ""
 
     def unexpected_error_match(self, line):
-        if re.search(r'^Unexpected: ', line) != None:
+        if re.search(r'^Unexpected: ', line) is not None:
             self.unexpected_errors[self.current_test][self.current_profile] = "true"
 
     def test_died(self):
diff --git a/scripts/thread_safety_generator.py b/scripts/thread_safety_generator.py
new file mode 100644
index 0000000..76196b1
--- /dev/null
+++ b/scripts/thread_safety_generator.py
@@ -0,0 +1,979 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2015-2019 The Khronos Group Inc.
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Mike Stroyan <stroyan@google.com>
+# Author: Mark Lobodzinski <mark@lunarg.com>
+
+import os,re,sys
+from generator import *
+from common_codegen import *
+
+# ThreadGeneratorOptions - subclass of GeneratorOptions.
+#
+# Adds options used by ThreadOutputGenerator objects during threading
+# layer generation.
+#
+# Additional members
+#   prefixText - list of strings to prefix generated header with
+#     (usually a copyright statement + calling convention macros).
+#   protectFile - True if multiple inclusion protection should be
+#     generated (based on the filename) around the entire header.
+#   protectFeature - True if #ifndef..#endif protection should be
+#     generated around a feature interface in the header file.
+#   genFuncPointers - True if function pointer typedefs should be
+#     generated
+#   protectProto - If conditional protection should be generated
+#     around prototype declarations, set to either '#ifdef'
+#     to require opt-in (#ifdef protectProtoStr) or '#ifndef'
+#     to require opt-out (#ifndef protectProtoStr). Otherwise
+#     set to None.
+#   protectProtoStr - #ifdef/#ifndef symbol to use around prototype
+#     declarations, if protectProto is set
+#   apicall - string to use for the function declaration prefix,
+#     such as APICALL on Windows.
+#   apientry - string to use for the calling convention macro,
+#     in typedefs, such as APIENTRY.
+#   apientryp - string to use for the calling convention macro
+#     in function pointer typedefs, such as APIENTRYP.
+#   indentFuncProto - True if prototype declarations should put each
+#     parameter on a separate line
+#   indentFuncPointer - True if typedefed function pointers should put each
+#     parameter on a separate line
+#   alignFuncParam - if nonzero and parameters are being put on a
+#     separate line, align parameter names at the specified column
+class ThreadGeneratorOptions(GeneratorOptions):
+    def __init__(self,
+                 filename = None,
+                 directory = '.',
+                 apiname = None,
+                 profile = None,
+                 versions = '.*',
+                 emitversions = '.*',
+                 defaultExtensions = None,
+                 addExtensions = None,
+                 removeExtensions = None,
+                 emitExtensions = None,
+                 sortProcedure = regSortFeatures,
+                 prefixText = "",
+                 genFuncPointers = True,
+                 protectFile = True,
+                 protectFeature = True,
+                 apicall = '',
+                 apientry = '',
+                 apientryp = '',
+                 indentFuncProto = True,
+                 indentFuncPointer = False,
+                 alignFuncParam = 0,
+                 expandEnumerants = True):
+        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
+                                  versions, emitversions, defaultExtensions,
+                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
+        self.prefixText      = prefixText
+        self.genFuncPointers = genFuncPointers
+        self.protectFile     = protectFile
+        self.protectFeature  = protectFeature
+        self.apicall         = apicall
+        self.apientry        = apientry
+        self.apientryp       = apientryp
+        self.indentFuncProto = indentFuncProto
+        self.indentFuncPointer = indentFuncPointer
+        self.alignFuncParam  = alignFuncParam
+        self.expandEnumerants = expandEnumerants
+
+
+# ThreadOutputGenerator - subclass of OutputGenerator.
+# Generates Thread checking framework
+#
+# ---- methods ----
+# ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for
+#   OutputGenerator. Defines additional internal state.
+# ---- methods overriding base class ----
+# beginFile(genOpts)
+# endFile()
+# beginFeature(interface, emit)
+# endFeature()
+# genType(typeinfo,name)
+# genStruct(typeinfo,name)
+# genGroup(groupinfo,name)
+# genEnum(enuminfo, name)
+# genCmd(cmdinfo)
+class ThreadOutputGenerator(OutputGenerator):
+    """Generate specified API interfaces in a specific style, such as a C header"""
+
+    inline_copyright_message = """
+// This file is ***GENERATED***.  Do Not Edit.
+// See layer_chassis_dispatch_generator.py for modifications.
+
+/* Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (c) 2015-2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ */"""
+
+ # Note that the inline_custom_header_preamble template below contains three embedded template expansion identifiers.
+ # These get replaced with generated code sections, and are labeled:
+ #  o COUNTER_CLASS_DEFINITIONS_TEMPLATE
+ #  o COUNTER_CLASS_INSTANCES_TEMPLATE
+ #  o COUNTER_CLASS_BODIES_TEMPLATE
+    inline_custom_header_preamble = """
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <vector>
+#include <unordered_set>
+#include <string>
+
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(DISTINCT_NONDISPATCHABLE_PHONY_HANDLE)
+// The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \
+    defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+// If pointers are 64-bit, then there can be separate counters for each
+// NONDISPATCHABLE_HANDLE type.  Otherwise they are all typedef uint64_t.
+#define DISTINCT_NONDISPATCHABLE_HANDLES
+// Make sure we catch any disagreement between us and the vulkan definition
+static_assert(std::is_pointer<DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value,
+              "Mismatched non-dispatchable handle handle, expected pointer type.");
+#else
+// Make sure we catch any disagreement between us and the vulkan definition
+static_assert(std::is_same<uint64_t, DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value,
+              "Mismatched non-dispatchable handle handle, expected uint64_t.");
+#endif
+
+// Suppress unused warning on Linux
+#if defined(__GNUC__)
+#define DECORATE_UNUSED __attribute__((unused))
+#else
+#define DECORATE_UNUSED
+#endif
+
+// clang-format off
+static const char DECORATE_UNUSED *kVUID_Threading_Info = "UNASSIGNED-Threading-Info";
+static const char DECORATE_UNUSED *kVUID_Threading_MultipleThreads = "UNASSIGNED-Threading-MultipleThreads";
+static const char DECORATE_UNUSED *kVUID_Threading_SingleThreadReuse = "UNASSIGNED-Threading-SingleThreadReuse";
+// clang-format on
+
+#undef DECORATE_UNUSED
+
+struct object_use_data {
+    loader_platform_thread_id thread;
+    int reader_count;
+    int writer_count;
+};
+
+// This is a wrapper around unordered_map that optimizes for the common case
+// of only containing a single element. The "first" element's use is stored
+// inline in the class and doesn't require hashing or memory (de)allocation.
+// TODO: Consider generalizing this from one element to N elements (where N
+// is a template parameter).
+template <typename Key, typename T>
+class small_unordered_map {
+
+    bool first_data_allocated;
+    Key first_data_key;
+    T first_data;
+
+    std::unordered_map<Key, T> uses;
+
+public:
+    small_unordered_map() : first_data_allocated(false) {}
+
+    bool contains(const Key& object) const {
+        if (first_data_allocated && object == first_data_key) {
+            return true;
+        // check size() first to avoid hashing object unnecessarily.
+        } else if (uses.size() == 0) {
+            return false;
+        } else {
+            return uses.find(object) != uses.end();
+        }
+    }
+
+    T& operator[](const Key& object) {
+        if (first_data_allocated && first_data_key == object) {
+            return first_data;
+        } else if (!first_data_allocated && uses.size() == 0) {
+            first_data_allocated = true;
+            first_data_key = object;
+            return first_data;
+        } else {
+            return uses[object];
+        }
+    }
+
+    typename std::unordered_map<Key, T>::size_type erase(const Key& object) {
+        if (first_data_allocated && first_data_key == object) {
+            first_data_allocated = false;
+            return 1;
+        } else {
+            return uses.erase(object);
+        }
+    }
+};
+
+template <typename T>
+class counter {
+public:
+    const char *typeName;
+    VkDebugReportObjectTypeEXT objectType;
+    debug_report_data **report_data;
+    small_unordered_map<T, object_use_data> uses;
+    std::mutex counter_lock;
+    std::condition_variable counter_condition;
+
+
+    void StartWrite(T object) {
+        if (object == VK_NULL_HANDLE) {
+            return;
+        }
+        bool skip = false;
+        loader_platform_thread_id tid = loader_platform_get_thread_id();
+        std::unique_lock<std::mutex> lock(counter_lock);
+        if (!uses.contains(object)) {
+            // There is no current use of the object.  Record writer thread.
+            struct object_use_data *use_data = &uses[object];
+            use_data->reader_count = 0;
+            use_data->writer_count = 1;
+            use_data->thread = tid;
+        } else {
+            struct object_use_data *use_data = &uses[object];
+            if (use_data->reader_count == 0) {
+                // There are no readers.  Two writers just collided.
+                if (use_data->thread != tid) {
+                    skip |= log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object),
+                        kVUID_Threading_MultipleThreads,
+                        "THREADING ERROR : object of type %s is simultaneously used in "
+                        "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
+                        typeName, (uint64_t)use_data->thread, (uint64_t)tid);
+                    if (skip) {
+                        // Wait for thread-safe access to object instead of skipping call.
+                        while (uses.contains(object)) {
+                            counter_condition.wait(lock);
+                        }
+                        // There is now no current use of the object.  Record writer thread.
+                        struct object_use_data *new_use_data = &uses[object];
+                        new_use_data->thread = tid;
+                        new_use_data->reader_count = 0;
+                        new_use_data->writer_count = 1;
+                    } else {
+                        // Continue with an unsafe use of the object.
+                        use_data->thread = tid;
+                        use_data->writer_count += 1;
+                    }
+                } else {
+                    // This is either safe multiple use in one call, or recursive use.
+                    // There is no way to make recursion safe.  Just forge ahead.
+                    use_data->writer_count += 1;
+                }
+            } else {
+                // There are readers.  This writer collided with them.
+                if (use_data->thread != tid) {
+                    skip |= log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object),
+                        kVUID_Threading_MultipleThreads,
+                        "THREADING ERROR : object of type %s is simultaneously used in "
+                        "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
+                        typeName, (uint64_t)use_data->thread, (uint64_t)tid);
+                    if (skip) {
+                        // Wait for thread-safe access to object instead of skipping call.
+                        while (uses.contains(object)) {
+                            counter_condition.wait(lock);
+                        }
+                        // There is now no current use of the object.  Record writer thread.
+                        struct object_use_data *new_use_data = &uses[object];
+                        new_use_data->thread = tid;
+                        new_use_data->reader_count = 0;
+                        new_use_data->writer_count = 1;
+                    } else {
+                        // Continue with an unsafe use of the object.
+                        use_data->thread = tid;
+                        use_data->writer_count += 1;
+                    }
+                } else {
+                    // This is either safe multiple use in one call, or recursive use.
+                    // There is no way to make recursion safe.  Just forge ahead.
+                    use_data->writer_count += 1;
+                }
+            }
+        }
+    }
+
+    void FinishWrite(T object) {
+        if (object == VK_NULL_HANDLE) {
+            return;
+        }
+        // Object is no longer in use
+        std::unique_lock<std::mutex> lock(counter_lock);
+        uses[object].writer_count -= 1;
+        if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) {
+            uses.erase(object);
+        }
+        // Notify any waiting threads that this object may be safe to use
+        lock.unlock();
+        counter_condition.notify_all();
+    }
+
+    void StartRead(T object) {
+        if (object == VK_NULL_HANDLE) {
+            return;
+        }
+        bool skip = false;
+        loader_platform_thread_id tid = loader_platform_get_thread_id();
+        std::unique_lock<std::mutex> lock(counter_lock);
+        if (!uses.contains(object)) {
+            // There is no current use of the object.  Record reader count
+            struct object_use_data *use_data = &uses[object];
+            use_data->reader_count = 1;
+            use_data->writer_count = 0;
+            use_data->thread = tid;
+        } else if (uses[object].writer_count > 0 && uses[object].thread != tid) {
+            // There is a writer of the object.
+            skip |= false;
+            log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), kVUID_Threading_MultipleThreads,
+                "THREADING ERROR : object of type %s is simultaneously used in "
+                "thread 0x%" PRIx64 " and thread 0x%" PRIx64,
+                typeName, (uint64_t)uses[object].thread, (uint64_t)tid);
+            if (skip) {
+                // Wait for thread-safe access to object instead of skipping call.
+                while (uses.contains(object)) {
+                    counter_condition.wait(lock);
+                }
+                // There is no current use of the object.  Record reader count
+                struct object_use_data *use_data = &uses[object];
+                use_data->reader_count = 1;
+                use_data->writer_count = 0;
+                use_data->thread = tid;
+            } else {
+                uses[object].reader_count += 1;
+            }
+        } else {
+            // There are other readers of the object.  Increase reader count
+            uses[object].reader_count += 1;
+        }
+    }
+    void FinishRead(T object) {
+        if (object == VK_NULL_HANDLE) {
+            return;
+        }
+        std::unique_lock<std::mutex> lock(counter_lock);
+        uses[object].reader_count -= 1;
+        if ((uses[object].reader_count == 0) && (uses[object].writer_count == 0)) {
+            uses.erase(object);
+        }
+        // Notify any waiting threads that this object may be safe to use
+        lock.unlock();
+        counter_condition.notify_all();
+    }
+    counter(const char *name = "", VkDebugReportObjectTypeEXT type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, debug_report_data **rep_data = nullptr) {
+        typeName = name;
+        objectType = type;
+        report_data = rep_data;
+    }
+};
+
+
+
+class ThreadSafety : public ValidationObject {
+public:
+
+    // Override chassis read/write locks for this validation object
+    // This override takes a deferred lock. i.e. it is not acquired.
+    std::unique_lock<std::mutex> write_lock() {
+        return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock);
+    }
+
+    std::mutex command_pool_lock;
+    std::unordered_map<VkCommandBuffer, VkCommandPool> command_pool_map;
+
+    counter<VkCommandBuffer> c_VkCommandBuffer;
+    counter<VkDevice> c_VkDevice;
+    counter<VkInstance> c_VkInstance;
+    counter<VkQueue> c_VkQueue;
+#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
+
+    // Special entry to allow tracking of command pool Reset and Destroy
+    counter<VkCommandPool> c_VkCommandPoolContents;
+COUNTER_CLASS_DEFINITIONS_TEMPLATE
+
+#else   // DISTINCT_NONDISPATCHABLE_HANDLES
+    // Special entry to allow tracking of command pool Reset and Destroy
+    counter<uint64_t> c_VkCommandPoolContents;
+
+    counter<uint64_t> c_uint64_t;
+#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
+
+    ThreadSafety()
+        : c_VkCommandBuffer("VkCommandBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, &report_data),
+          c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, &report_data),
+          c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, &report_data),
+          c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, &report_data),
+          c_VkCommandPoolContents("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, &report_data),
+
+#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
+COUNTER_CLASS_INSTANCES_TEMPLATE
+
+
+#else   // DISTINCT_NONDISPATCHABLE_HANDLES
+          c_uint64_t("NON_DISPATCHABLE_HANDLE", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, &report_data)
+#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
+              {};
+
+#define WRAPPER(type)                                                \
+    void StartWriteObject(type object) {                             \
+        c_##type.StartWrite(object);                                 \
+    }                                                                \
+    void FinishWriteObject(type object) {                            \
+        c_##type.FinishWrite(object);                                \
+    }                                                                \
+    void StartReadObject(type object) {                              \
+        c_##type.StartRead(object);                                  \
+    }                                                                \
+    void FinishReadObject(type object) {                             \
+        c_##type.FinishRead(object);                                 \
+    }
+
+WRAPPER(VkDevice)
+WRAPPER(VkInstance)
+WRAPPER(VkQueue)
+#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
+COUNTER_CLASS_BODIES_TEMPLATE
+
+#else   // DISTINCT_NONDISPATCHABLE_HANDLES
+WRAPPER(uint64_t)
+#endif  // DISTINCT_NONDISPATCHABLE_HANDLES
+
+    // VkCommandBuffer needs check for implicit use of command pool
+    void StartWriteObject(VkCommandBuffer object, bool lockPool = true) {
+        if (lockPool) {
+            std::unique_lock<std::mutex> lock(command_pool_lock);
+            VkCommandPool pool = command_pool_map[object];
+            lock.unlock();
+            StartWriteObject(pool);
+        }
+        c_VkCommandBuffer.StartWrite(object);
+    }
+    void FinishWriteObject(VkCommandBuffer object, bool lockPool = true) {
+        c_VkCommandBuffer.FinishWrite(object);
+        if (lockPool) {
+            std::unique_lock<std::mutex> lock(command_pool_lock);
+            VkCommandPool pool = command_pool_map[object];
+            lock.unlock();
+            FinishWriteObject(pool);
+        }
+    }
+    void StartReadObject(VkCommandBuffer object) {
+        std::unique_lock<std::mutex> lock(command_pool_lock);
+        VkCommandPool pool = command_pool_map[object];
+        lock.unlock();
+        // We set up a read guard against the "Contents" counter to catch conflict vs. vkResetCommandPool and vkDestroyCommandPool
+        // while *not* establishing a read guard against the command pool counter itself to avoid false postives for
+        // non-externally sync'd command buffers
+        c_VkCommandPoolContents.StartRead(pool);
+        c_VkCommandBuffer.StartRead(object);
+    }
+    void FinishReadObject(VkCommandBuffer object) {
+        c_VkCommandBuffer.FinishRead(object);
+        std::unique_lock<std::mutex> lock(command_pool_lock);
+        VkCommandPool pool = command_pool_map[object];
+        lock.unlock();
+        c_VkCommandPoolContents.FinishRead(pool);
+    } """
+
+
+    inline_custom_source_preamble = """
+void ThreadSafety::PreCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
+                                                       VkCommandBuffer *pCommandBuffers) {
+    StartReadObject(device);
+    StartWriteObject(pAllocateInfo->commandPool);
+}
+
+void ThreadSafety::PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo,
+                                                        VkCommandBuffer *pCommandBuffers, VkResult result) {
+    FinishReadObject(device);
+    FinishWriteObject(pAllocateInfo->commandPool);
+
+    // Record mapping from command buffer to command pool
+    for (uint32_t index = 0; index < pAllocateInfo->commandBufferCount; index++) {
+        std::lock_guard<std::mutex> lock(command_pool_lock);
+        command_pool_map[pCommandBuffers[index]] = pAllocateInfo->commandPool;
+    }
+}
+
+void ThreadSafety::PreCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                       VkDescriptorSet *pDescriptorSets) {
+    StartReadObject(device);
+    StartWriteObject(pAllocateInfo->descriptorPool);
+    // Host access to pAllocateInfo::descriptorPool must be externally synchronized
+}
+
+void ThreadSafety::PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
+                                                        VkDescriptorSet *pDescriptorSets, VkResult result) {
+    FinishReadObject(device);
+    FinishWriteObject(pAllocateInfo->descriptorPool);
+    // Host access to pAllocateInfo::descriptorPool must be externally synchronized
+}
+
+void ThreadSafety::PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                   const VkCommandBuffer *pCommandBuffers) {
+    const bool lockCommandPool = false;  // pool is already directly locked
+    StartReadObject(device);
+    StartWriteObject(commandPool);
+    for (uint32_t index = 0; index < commandBufferCount; index++) {
+        StartWriteObject(pCommandBuffers[index], lockCommandPool);
+    }
+    // The driver may immediately reuse command buffers in another thread.
+    // These updates need to be done before calling down to the driver.
+    for (uint32_t index = 0; index < commandBufferCount; index++) {
+        FinishWriteObject(pCommandBuffers[index], lockCommandPool);
+        std::lock_guard<std::mutex> lock(command_pool_lock);
+        command_pool_map.erase(pCommandBuffers[index]);
+    }
+}
+
+void ThreadSafety::PostCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                                                    const VkCommandBuffer *pCommandBuffers) {
+    FinishReadObject(device);
+    FinishWriteObject(commandPool);
+}
+
+void ThreadSafety::PreCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
+    StartReadObject(device);
+    StartWriteObject(commandPool);
+    // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+    c_VkCommandPoolContents.StartWrite(commandPool);
+    // Host access to commandPool must be externally synchronized
+}
+
+void ThreadSafety::PostCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags, VkResult result) {
+    FinishReadObject(device);
+    FinishWriteObject(commandPool);
+    c_VkCommandPoolContents.FinishWrite(commandPool);
+    // Host access to commandPool must be externally synchronized
+}
+
+void ThreadSafety::PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
+    StartReadObject(device);
+    StartWriteObject(commandPool);
+    // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+    c_VkCommandPoolContents.StartWrite(commandPool);
+    // Host access to commandPool must be externally synchronized
+}
+
+void ThreadSafety::PostCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
+    FinishReadObject(device);
+    FinishWriteObject(commandPool);
+    c_VkCommandPoolContents.FinishWrite(commandPool);
+}
+
+// GetSwapchainImages can return a non-zero count with a NULL pSwapchainImages pointer.  Let's avoid crashes by ignoring
+// pSwapchainImages.
+void ThreadSafety::PreCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                      VkImage *pSwapchainImages) {
+    StartReadObject(device);
+    StartReadObject(swapchain);
+}
+
+void ThreadSafety::PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                       VkImage *pSwapchainImages, VkResult result) {
+    FinishReadObject(device);
+    FinishReadObject(swapchain);
+}
+
+"""
+
+
+    # This is an ordered list of sections in the header file.
+    ALL_SECTIONS = ['command']
+    def __init__(self,
+                 errFile = sys.stderr,
+                 warnFile = sys.stderr,
+                 diagFile = sys.stdout):
+        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+        # Internal state - accumulators for different inner block text
+        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+        self.non_dispatchable_types = set()
+        self.object_to_debug_report_type = {
+            'VkInstance' : 'VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT',
+            'VkPhysicalDevice' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT',
+            'VkDevice' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT',
+            'VkQueue' : 'VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT',
+            'VkSemaphore' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT',
+            'VkCommandBuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT',
+            'VkFence' : 'VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT',
+            'VkDeviceMemory' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT',
+            'VkBuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT',
+            'VkImage' : 'VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT',
+            'VkEvent' : 'VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT',
+            'VkQueryPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT',
+            'VkBufferView' : 'VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT',
+            'VkImageView' : 'VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT',
+            'VkShaderModule' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT',
+            'VkPipelineCache' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT',
+            'VkPipelineLayout' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT',
+            'VkRenderPass' : 'VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT',
+            'VkPipeline' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT',
+            'VkDescriptorSetLayout' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT',
+            'VkSampler' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT',
+            'VkDescriptorPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT',
+            'VkDescriptorSet' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT',
+            'VkFramebuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT',
+            'VkCommandPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT',
+            'VkSurfaceKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT',
+            'VkSwapchainKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT',
+            'VkDisplayKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT',
+            'VkDisplayModeKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT',
+            'VkObjectTableNVX' : 'VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT',
+            'VkIndirectCommandsLayoutNVX' : 'VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT',
+            'VkSamplerYcbcrConversion' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT',
+            'VkDescriptorUpdateTemplate' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT',
+            'VkAccelerationStructureNV' : 'VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT',
+            'VkDebugReportCallbackEXT' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT',
+            'VkValidationCacheEXT' : 'VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT' }
+
+    # Check if the parameter passed in is a pointer to an array
+    def paramIsArray(self, param):
+        return param.attrib.get('len') is not None
+
+    # Check if the parameter passed in is a pointer
+    def paramIsPointer(self, param):
+        ispointer = False
+        for elem in param:
+            if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
+                ispointer = True
+        return ispointer
+
+    # Check if an object is a non-dispatchable handle
+    def isHandleTypeNonDispatchable(self, handletype):
+        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+        if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
+            return True
+        else:
+            return False
+
+    # Check if an object is a dispatchable handle
+    def isHandleTypeDispatchable(self, handletype):
+        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+        if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
+            return True
+        else:
+            return False
+
+    def makeThreadUseBlock(self, cmd, functionprefix):
+        """Generate C function pointer typedef for <command> Element"""
+        paramdecl = ''
+        # Find and add any parameters that are thread unsafe
+        params = cmd.findall('param')
+        for param in params:
+            paramname = param.find('name')
+            if False: # self.paramIsPointer(param):
+                paramdecl += '    // not watching use of pointer ' + paramname.text + '\n'
+            else:
+                externsync = param.attrib.get('externsync')
+                if externsync == 'true':
+                    if self.paramIsArray(param):
+                        paramdecl += 'for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
+                        paramdecl += '    ' + functionprefix + 'WriteObject(' + paramname.text + '[index]);\n'
+                        paramdecl += '}\n'
+                    else:
+                        paramdecl += functionprefix + 'WriteObject(' + paramname.text + ');\n'
+                elif (param.attrib.get('externsync')):
+                    if self.paramIsArray(param):
+                        # Externsync can list pointers to arrays of members to synchronize
+                        paramdecl += 'for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
+                        second_indent = ''
+                        for member in externsync.split(","):
+                            # Replace first empty [] in member name with index
+                            element = member.replace('[]','[index]',1)
+                            if '[]' in element:
+                                # TODO: These null checks can be removed if threading ends up behind parameter
+                                #       validation in layer order
+                                element_ptr = element.split('[]')[0]
+                                paramdecl += '    if (' + element_ptr + ') {\n'
+                                # Replace any second empty [] in element name with inner array index based on mapping array
+                                # names like "pSomeThings[]" to "someThingCount" array size. This could be more robust by
+                                # mapping a param member name to a struct type and "len" attribute.
+                                limit = element[0:element.find('s[]')] + 'Count'
+                                dotp = limit.rfind('.p')
+                                limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:]
+                                paramdecl += '        for(uint32_t index2=0;index2<'+limit+';index2++) {\n'
+                                element = element.replace('[]','[index2]')
+                                second_indent = '   '
+                                paramdecl += '        ' + second_indent + functionprefix + 'WriteObject(' + element + ');\n'
+                                paramdecl += '        }\n'
+                                paramdecl += '    }\n'
+                            else:
+                                paramdecl += '    ' + second_indent + functionprefix + 'WriteObject(' + element + ');\n'
+                        paramdecl += '}\n'
+                    else:
+                        # externsync can list members to synchronize
+                        for member in externsync.split(","):
+                            member = str(member).replace("::", "->")
+                            member = str(member).replace(".", "->")
+                            paramdecl += '    ' + functionprefix + 'WriteObject(' + member + ');\n'
+                else:
+                    paramtype = param.find('type')
+                    if paramtype is not None:
+                        paramtype = paramtype.text
+                    else:
+                        paramtype = 'None'
+                    if (self.isHandleTypeDispatchable(paramtype) or self.isHandleTypeNonDispatchable(paramtype)) and paramtype != 'VkPhysicalDevice':
+                        if self.paramIsArray(param) and ('pPipelines' != paramname.text):
+                            # Add pointer dereference for array counts that are pointer values
+                            dereference = ''
+                            for candidate in params:
+                                if param.attrib.get('len') == candidate.find('name').text:
+                                    if self.paramIsPointer(candidate):
+                                        dereference = '*'
+                            param_len = str(param.attrib.get('len')).replace("::", "->")
+                            paramdecl += 'for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n'
+                            paramdecl += '    ' + functionprefix + 'ReadObject(' + paramname.text + '[index]);\n'
+                            paramdecl += '}\n'
+                        elif not self.paramIsPointer(param):
+                            # Pointer params are often being created.
+                            # They are not being read from.
+                            paramdecl += functionprefix + 'ReadObject(' + paramname.text + ');\n'
+        explicitexternsyncparams = cmd.findall("param[@externsync]")
+        if (explicitexternsyncparams is not None):
+            for param in explicitexternsyncparams:
+                externsyncattrib = param.attrib.get('externsync')
+                paramname = param.find('name')
+                paramdecl += '// Host access to '
+                if externsyncattrib == 'true':
+                    if self.paramIsArray(param):
+                        paramdecl += 'each member of ' + paramname.text
+                    elif self.paramIsPointer(param):
+                        paramdecl += 'the object referenced by ' + paramname.text
+                    else:
+                        paramdecl += paramname.text
+                else:
+                    paramdecl += externsyncattrib
+                paramdecl += ' must be externally synchronized\n'
+
+        # Find and add any "implicit" parameters that are thread unsafe
+        implicitexternsyncparams = cmd.find('implicitexternsyncparams')
+        if (implicitexternsyncparams is not None):
+            for elem in implicitexternsyncparams:
+                paramdecl += '// '
+                paramdecl += elem.text
+                paramdecl += ' must be externally synchronized between host accesses\n'
+
+        if (paramdecl == ''):
+            return None
+        else:
+            return paramdecl
+    def beginFile(self, genOpts):
+        OutputGenerator.beginFile(self, genOpts)
+        #
+        # TODO: LUGMAL -- remove this and add our copyright
+        # User-supplied prefix text, if any (list of strings)
+        write(self.inline_copyright_message, file=self.outFile)
+
+        self.header_file = (genOpts.filename == 'thread_safety.h')
+        self.source_file = (genOpts.filename == 'thread_safety.cpp')
+
+        if not self.header_file and not self.source_file:
+            print("Error: Output Filenames have changed, update generator source.\n")
+            sys.exit(1)
+
+        if self.source_file:
+            write('#include "chassis.h"', file=self.outFile)
+            write('#include "thread_safety.h"', file=self.outFile)
+            self.newline()
+            write(self.inline_custom_source_preamble, file=self.outFile)
+
+
+    def endFile(self):
+
+        # Create class definitions
+        counter_class_defs = ''
+        counter_class_instances = ''
+        counter_class_bodies = ''
+
+        for obj in self.non_dispatchable_types:
+            counter_class_defs += '    counter<%s> c_%s;\n' % (obj, obj)
+            if obj in self.object_to_debug_report_type:
+                obj_type = self.object_to_debug_report_type[obj]
+            else:
+                obj_type = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT'
+            counter_class_instances += '          c_%s("%s", %s, &report_data),\n' % (obj, obj, obj_type)
+            counter_class_bodies += 'WRAPPER(%s)\n' % obj
+        if self.header_file:
+            class_def = self.inline_custom_header_preamble.replace('COUNTER_CLASS_DEFINITIONS_TEMPLATE', counter_class_defs)
+            class_def = class_def.replace('COUNTER_CLASS_INSTANCES_TEMPLATE', counter_class_instances[:-2]) # Kill last comma
+            class_def = class_def.replace('COUNTER_CLASS_BODIES_TEMPLATE', counter_class_bodies)
+            write(class_def, file=self.outFile)
+        write('\n'.join(self.sections['command']), file=self.outFile)
+        if self.header_file:
+            write('};', file=self.outFile)
+
+        # Finish processing in superclass
+        OutputGenerator.endFile(self)
+
+    def beginFeature(self, interface, emit):
+        #write('// starting beginFeature', file=self.outFile)
+        # Start processing in superclass
+        OutputGenerator.beginFeature(self, interface, emit)
+        # C-specific
+        # Accumulate includes, defines, types, enums, function pointer typedefs,
+        # end function prototypes separately for this feature. They're only
+        # printed in endFeature().
+        self.featureExtraProtect = GetFeatureProtect(interface)
+        if (self.featureExtraProtect is not None):
+            self.appendSection('command', '\n#ifdef %s' % self.featureExtraProtect)
+
+        #write('// ending beginFeature', file=self.outFile)
+    def endFeature(self):
+        # C-specific
+        if (self.emit):
+            if (self.featureExtraProtect is not None):
+                self.appendSection('command', '#endif // %s' % self.featureExtraProtect)
+        # Finish processing in superclass
+        OutputGenerator.endFeature(self)
+    #
+    # Append a definition to the specified section
+    def appendSection(self, section, text):
+        self.sections[section].append(text)
+    #
+    # Type generation
+    def genType(self, typeinfo, name, alias):
+        OutputGenerator.genType(self, typeinfo, name, alias)
+        type_elem = typeinfo.elem
+        category = type_elem.get('category')
+        if category == 'handle':
+            if self.isHandleTypeNonDispatchable(name):
+                self.non_dispatchable_types.add(name)
+    #
+    # Struct (e.g. C "struct" type) generation.
+    # This is a special case of the <type> tag where the contents are
+    # interpreted as a set of <member> tags instead of freeform C
+    # C type declarations. The <member> tags are just like <param>
+    # tags - they are a declaration of a struct or union member.
+    # Only simple member declarations are supported (no nested
+    # structs etc.)
+    def genStruct(self, typeinfo, typeName, alias):
+        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
+        body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
+        # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
+        for member in typeinfo.elem.findall('.//member'):
+            body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
+            body += ';\n'
+        body += '} ' + typeName + ';\n'
+        self.appendSection('struct', body)
+    #
+    # Group (e.g. C "enum" type) generation.
+    # These are concatenated together with other types.
+    def genGroup(self, groupinfo, groupName, alias):
+        pass
+    # Enumerant generation
+    # <enum> tags may specify their values in several ways, but are usually
+    # just integers.
+    def genEnum(self, enuminfo, name, alias):
+        pass
+    #
+    # Command generation
+    def genCmd(self, cmdinfo, name, alias):
+        # Commands shadowed by interface functions and are not implemented
+        special_functions = [
+            'vkCreateDevice',
+            'vkCreateInstance',
+            'vkAllocateCommandBuffers',
+            'vkFreeCommandBuffers',
+            'vkResetCommandPool',
+            'vkDestroyCommandPool',
+            'vkAllocateDescriptorSets',
+            'vkQueuePresentKHR',
+            'vkGetSwapchainImagesKHR',
+        ]
+        if name == 'vkQueuePresentKHR' or (name in special_functions and self.source_file):
+            return
+
+        if (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name):
+            self.appendSection('command', '// TODO - not wrapping EXT function ' + name)
+            return
+
+        # Determine first if this function needs to be intercepted
+        startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Start')
+        if startthreadsafety is None:
+            return
+        finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Finish')
+
+        OutputGenerator.genCmd(self, cmdinfo, name, alias)
+
+        # setup common to call wrappers
+        # first parameter is always dispatchable
+        dispatchable_type = cmdinfo.elem.find('param/type').text
+        dispatchable_name = cmdinfo.elem.find('param/name').text
+
+        decls = self.makeCDecls(cmdinfo.elem)
+
+        result_type = cmdinfo.elem.find('proto/type')
+
+        if self.source_file:
+            pre_decl = decls[0][:-1]
+            pre_decl = pre_decl.split("VKAPI_CALL ")[1]
+            pre_decl = 'void ThreadSafety::PreCallRecord' + pre_decl + ' {'
+
+            # PreCallRecord
+            self.appendSection('command', '')
+            self.appendSection('command', pre_decl)
+            self.appendSection('command', "    " + "\n    ".join(str(startthreadsafety).rstrip().split("\n")))
+            self.appendSection('command', '}')
+
+            # PostCallRecord
+            post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord')
+            if result_type.text == 'VkResult':
+                post_decl = post_decl.replace(')', ',\n    VkResult                                    result)')
+            self.appendSection('command', '')
+            self.appendSection('command', post_decl)
+            self.appendSection('command', "    " + "\n    ".join(str(finishthreadsafety).rstrip().split("\n")))
+            self.appendSection('command', '}')
+
+        if self.header_file:
+            pre_decl = decls[0][:-1]
+            pre_decl = pre_decl.split("VKAPI_CALL ")[1]
+            pre_decl = 'void PreCallRecord' + pre_decl + ';'
+
+            # PreCallRecord
+            self.appendSection('command', '')
+            self.appendSection('command', pre_decl)
+
+            # PostCallRecord
+            post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord')
+            if result_type.text == 'VkResult':
+                post_decl = post_decl.replace(')', ',\n    VkResult                                    result)')
+            self.appendSection('command', '')
+            self.appendSection('command', post_decl)
+
+    #
+    # override makeProtoName to drop the "vk" prefix
+    def makeProtoName(self, name, tail):
+        return self.genOpts.apientry + name[2:] + tail
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
deleted file mode 100644
index 5cfb4d7..0000000
--- a/scripts/threading_generator.py
+++ /dev/null
@@ -1,458 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2015-2016 The Khronos Group Inc.
-# Copyright (c) 2015-2016 Valve Corporation
-# Copyright (c) 2015-2016 LunarG, Inc.
-# Copyright (c) 2015-2016 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Author: Mike Stroyan <stroyan@google.com>
-# Author: Mark Lobodzinski <mark@lunarg.com>
-
-import os,re,sys
-from generator import *
-from common_codegen import *
-
-# ThreadGeneratorOptions - subclass of GeneratorOptions.
-#
-# Adds options used by ThreadOutputGenerator objects during threading
-# layer generation.
-#
-# Additional members
-#   prefixText - list of strings to prefix generated header with
-#     (usually a copyright statement + calling convention macros).
-#   protectFile - True if multiple inclusion protection should be
-#     generated (based on the filename) around the entire header.
-#   protectFeature - True if #ifndef..#endif protection should be
-#     generated around a feature interface in the header file.
-#   genFuncPointers - True if function pointer typedefs should be
-#     generated
-#   protectProto - If conditional protection should be generated
-#     around prototype declarations, set to either '#ifdef'
-#     to require opt-in (#ifdef protectProtoStr) or '#ifndef'
-#     to require opt-out (#ifndef protectProtoStr). Otherwise
-#     set to None.
-#   protectProtoStr - #ifdef/#ifndef symbol to use around prototype
-#     declarations, if protectProto is set
-#   apicall - string to use for the function declaration prefix,
-#     such as APICALL on Windows.
-#   apientry - string to use for the calling convention macro,
-#     in typedefs, such as APIENTRY.
-#   apientryp - string to use for the calling convention macro
-#     in function pointer typedefs, such as APIENTRYP.
-#   indentFuncProto - True if prototype declarations should put each
-#     parameter on a separate line
-#   indentFuncPointer - True if typedefed function pointers should put each
-#     parameter on a separate line
-#   alignFuncParam - if nonzero and parameters are being put on a
-#     separate line, align parameter names at the specified column
-class ThreadGeneratorOptions(GeneratorOptions):
-    def __init__(self,
-                 filename = None,
-                 directory = '.',
-                 apiname = None,
-                 profile = None,
-                 versions = '.*',
-                 emitversions = '.*',
-                 defaultExtensions = None,
-                 addExtensions = None,
-                 removeExtensions = None,
-                 emitExtensions = None,
-                 sortProcedure = regSortFeatures,
-                 prefixText = "",
-                 genFuncPointers = True,
-                 protectFile = True,
-                 protectFeature = True,
-                 apicall = '',
-                 apientry = '',
-                 apientryp = '',
-                 indentFuncProto = True,
-                 indentFuncPointer = False,
-                 alignFuncParam = 0,
-                 expandEnumerants = True):
-        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
-        self.prefixText      = prefixText
-        self.genFuncPointers = genFuncPointers
-        self.protectFile     = protectFile
-        self.protectFeature  = protectFeature
-        self.apicall         = apicall
-        self.apientry        = apientry
-        self.apientryp       = apientryp
-        self.indentFuncProto = indentFuncProto
-        self.indentFuncPointer = indentFuncPointer
-        self.alignFuncParam  = alignFuncParam
-        self.expandEnumerants = expandEnumerants
-
-
-# ThreadOutputGenerator - subclass of OutputGenerator.
-# Generates Thread checking framework
-#
-# ---- methods ----
-# ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for
-#   OutputGenerator. Defines additional internal state.
-# ---- methods overriding base class ----
-# beginFile(genOpts)
-# endFile()
-# beginFeature(interface, emit)
-# endFeature()
-# genType(typeinfo,name)
-# genStruct(typeinfo,name)
-# genGroup(groupinfo,name)
-# genEnum(enuminfo, name)
-# genCmd(cmdinfo)
-class ThreadOutputGenerator(OutputGenerator):
-    """Generate specified API interfaces in a specific style, such as a C header"""
-    # This is an ordered list of sections in the header file.
-    TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
-                     'group', 'bitmask', 'funcpointer', 'struct']
-    ALL_SECTIONS = TYPE_SECTIONS + ['command']
-    def __init__(self,
-                 errFile = sys.stderr,
-                 warnFile = sys.stderr,
-                 diagFile = sys.stdout):
-        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
-        # Internal state - accumulators for different inner block text
-        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
-        self.intercepts = []
-
-    # Check if the parameter passed in is a pointer to an array
-    def paramIsArray(self, param):
-        return param.attrib.get('len') is not None
-
-    # Check if the parameter passed in is a pointer
-    def paramIsPointer(self, param):
-        ispointer = False
-        for elem in param:
-            if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
-                ispointer = True
-        return ispointer
-
-    # Check if an object is a non-dispatchable handle
-    def isHandleTypeNonDispatchable(self, handletype):
-        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
-        if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
-            return True
-        else:
-            return False
-
-    # Check if an object is a dispatchable handle
-    def isHandleTypeDispatchable(self, handletype):
-        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
-        if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
-            return True
-        else:
-            return False
-
-    def makeThreadUseBlock(self, cmd, functionprefix):
-        """Generate C function pointer typedef for <command> Element"""
-        paramdecl = ''
-        # Find and add any parameters that are thread unsafe
-        params = cmd.findall('param')
-        for param in params:
-            paramname = param.find('name')
-            if False: # self.paramIsPointer(param):
-                paramdecl += '    // not watching use of pointer ' + paramname.text + '\n'
-            else:
-                externsync = param.attrib.get('externsync')
-                if externsync == 'true':
-                    if self.paramIsArray(param):
-                        paramdecl += '    for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
-                        paramdecl += '        ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + '[index]);\n'
-                        paramdecl += '    }\n'
-                    else:
-                        paramdecl += '    ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + ');\n'
-                elif (param.attrib.get('externsync')):
-                    if self.paramIsArray(param):
-                        # Externsync can list pointers to arrays of members to synchronize
-                        paramdecl += '    for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n'
-                        for member in externsync.split(","):
-                            # Replace first empty [] in member name with index
-                            element = member.replace('[]','[index]',1)
-                            if '[]' in element:
-                                # Replace any second empty [] in element name with
-                                # inner array index based on mapping array names like
-                                # "pSomeThings[]" to "someThingCount" array size.
-                                # This could be more robust by mapping a param member
-                                # name to a struct type and "len" attribute.
-                                limit = element[0:element.find('s[]')] + 'Count'
-                                dotp = limit.rfind('.p')
-                                limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:]
-                                paramdecl += '        for(uint32_t index2=0;index2<'+limit+';index2++)\n'
-                                element = element.replace('[]','[index2]')
-                            paramdecl += '            ' + functionprefix + 'WriteObject(my_data, ' + element + ');\n'
-                        paramdecl += '    }\n'
-                    else:
-                        # externsync can list members to synchronize
-                        for member in externsync.split(","):
-                            member = str(member).replace("::", "->")
-                            member = str(member).replace(".", "->")
-                            paramdecl += '    ' + functionprefix + 'WriteObject(my_data, ' + member + ');\n'
-                else:
-                    paramtype = param.find('type')
-                    if paramtype is not None:
-                        paramtype = paramtype.text
-                    else:
-                        paramtype = 'None'
-                    if (self.isHandleTypeDispatchable(paramtype) or self.isHandleTypeNonDispatchable(paramtype)) and paramtype != 'VkPhysicalDevice':
-                        if self.paramIsArray(param) and ('pPipelines' != paramname.text):
-                            # Add pointer dereference for array counts that are pointer values
-                            dereference = ''
-                            for candidate in params:
-                                if param.attrib.get('len') == candidate.find('name').text:
-                                    if self.paramIsPointer(candidate):
-                                        dereference = '*'
-                            param_len = str(param.attrib.get('len')).replace("::", "->")
-                            paramdecl += '    for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n'
-                            paramdecl += '        ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + '[index]);\n'
-                            paramdecl += '    }\n'
-                        elif not self.paramIsPointer(param):
-                            # Pointer params are often being created.
-                            # They are not being read from.
-                            paramdecl += '    ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + ');\n'
-        explicitexternsyncparams = cmd.findall("param[@externsync]")
-        if (explicitexternsyncparams is not None):
-            for param in explicitexternsyncparams:
-                externsyncattrib = param.attrib.get('externsync')
-                paramname = param.find('name')
-                paramdecl += '    // Host access to '
-                if externsyncattrib == 'true':
-                    if self.paramIsArray(param):
-                        paramdecl += 'each member of ' + paramname.text
-                    elif self.paramIsPointer(param):
-                        paramdecl += 'the object referenced by ' + paramname.text
-                    else:
-                        paramdecl += paramname.text
-                else:
-                    paramdecl += externsyncattrib
-                paramdecl += ' must be externally synchronized\n'
-
-        # Find and add any "implicit" parameters that are thread unsafe
-        implicitexternsyncparams = cmd.find('implicitexternsyncparams')
-        if (implicitexternsyncparams is not None):
-            for elem in implicitexternsyncparams:
-                paramdecl += '    // '
-                paramdecl += elem.text
-                paramdecl += ' must be externally synchronized between host accesses\n'
-
-        if (paramdecl == ''):
-            return None
-        else:
-            return paramdecl
-    def beginFile(self, genOpts):
-        OutputGenerator.beginFile(self, genOpts)
-        # C-specific
-        #
-        # Multiple inclusion protection & C++ namespace.
-        if (genOpts.protectFile and self.genOpts.filename):
-            headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename))
-            write('#ifndef', headerSym, file=self.outFile)
-            write('#define', headerSym, '1', file=self.outFile)
-            self.newline()
-        write('namespace threading {', file=self.outFile)
-        self.newline()
-        #
-        # User-supplied prefix text, if any (list of strings)
-        if (genOpts.prefixText):
-            for s in genOpts.prefixText:
-                write(s, file=self.outFile)
-    def endFile(self):
-        # C-specific
-        # Finish C++ namespace and multiple inclusion protection
-        self.newline()
-        # record intercepted procedures
-        write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
-        write('\n'.join(self.intercepts), file=self.outFile)
-        write('};\n', file=self.outFile)
-        self.newline()
-        write('} // namespace threading', file=self.outFile)
-        if (self.genOpts.protectFile and self.genOpts.filename):
-            self.newline()
-            write('#endif', file=self.outFile)
-        # Finish processing in superclass
-        OutputGenerator.endFile(self)
-    def beginFeature(self, interface, emit):
-        #write('// starting beginFeature', file=self.outFile)
-        # Start processing in superclass
-        OutputGenerator.beginFeature(self, interface, emit)
-        # C-specific
-        # Accumulate includes, defines, types, enums, function pointer typedefs,
-        # end function prototypes separately for this feature. They're only
-        # printed in endFeature().
-        self.featureExtraProtect = GetFeatureProtect(interface)
-        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
-        #write('// ending beginFeature', file=self.outFile)
-    def endFeature(self):
-        # C-specific
-        # Actually write the interface to the output file.
-        #write('// starting endFeature', file=self.outFile)
-        if (self.emit):
-            self.newline()
-            if (self.genOpts.protectFeature):
-                write('#ifndef', self.featureName, file=self.outFile)
-            # If type declarations are needed by other features based on
-            # this one, it may be necessary to suppress the ExtraProtect,
-            # or move it below the 'for section...' loop.
-            #write('// endFeature looking at self.featureExtraProtect', file=self.outFile)
-            if (self.featureExtraProtect != None):
-                write('#ifdef', self.featureExtraProtect, file=self.outFile)
-            #write('#define', self.featureName, '1', file=self.outFile)
-            for section in self.TYPE_SECTIONS:
-                #write('// endFeature writing section'+section, file=self.outFile)
-                contents = self.sections[section]
-                if contents:
-                    write('\n'.join(contents), file=self.outFile)
-                    self.newline()
-            #write('// endFeature looking at self.sections[command]', file=self.outFile)
-            if (self.sections['command']):
-                write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
-                self.newline()
-            if (self.featureExtraProtect != None):
-                write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
-            if (self.genOpts.protectFeature):
-                write('#endif /*', self.featureName, '*/', file=self.outFile)
-        # Finish processing in superclass
-        OutputGenerator.endFeature(self)
-        #write('// ending endFeature', file=self.outFile)
-    #
-    # Append a definition to the specified section
-    def appendSection(self, section, text):
-        # self.sections[section].append('SECTION: ' + section + '\n')
-        self.sections[section].append(text)
-    #
-    # Type generation
-    def genType(self, typeinfo, name, alias):
-        pass
-    #
-    # Struct (e.g. C "struct" type) generation.
-    # This is a special case of the <type> tag where the contents are
-    # interpreted as a set of <member> tags instead of freeform C
-    # C type declarations. The <member> tags are just like <param>
-    # tags - they are a declaration of a struct or union member.
-    # Only simple member declarations are supported (no nested
-    # structs etc.)
-    def genStruct(self, typeinfo, typeName, alias):
-        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-        body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
-        # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
-        for member in typeinfo.elem.findall('.//member'):
-            body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
-            body += ';\n'
-        body += '} ' + typeName + ';\n'
-        self.appendSection('struct', body)
-    #
-    # Group (e.g. C "enum" type) generation.
-    # These are concatenated together with other types.
-    def genGroup(self, groupinfo, groupName, alias):
-        pass
-    # Enumerant generation
-    # <enum> tags may specify their values in several ways, but are usually
-    # just integers.
-    def genEnum(self, enuminfo, name, alias):
-        pass
-    #
-    # Command generation
-    def genCmd(self, cmdinfo, name, alias):
-        # Commands shadowed by interface functions and are not implemented
-        special_functions = [
-            'vkGetDeviceProcAddr',
-            'vkGetInstanceProcAddr',
-            'vkCreateDevice',
-            'vkDestroyDevice',
-            'vkCreateInstance',
-            'vkDestroyInstance',
-            'vkAllocateCommandBuffers',
-            'vkFreeCommandBuffers',
-            'vkCreateDebugReportCallbackEXT',
-            'vkDestroyDebugReportCallbackEXT',
-            'vkAllocateDescriptorSets',
-            'vkGetSwapchainImagesKHR',
-            'vkEnumerateInstanceLayerProperties',
-            'vkEnumerateInstanceExtensionProperties',
-            'vkEnumerateDeviceLayerProperties',
-            'vkEnumerateDeviceExtensionProperties',
-            'vkCreateDebugUtilsMessengerEXT',
-            'vkDestroyDebugUtilsMessengerEXT',
-        ]
-        if name in special_functions:
-            decls = self.makeCDecls(cmdinfo.elem)
-            self.appendSection('command', '')
-            self.appendSection('command', '// declare only')
-            self.appendSection('command', decls[0])
-            self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
-            return
-        if "QueuePresentKHR" in name or (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name):
-            self.appendSection('command', '// TODO - not wrapping EXT function ' + name)
-            return
-        # Determine first if this function needs to be intercepted
-        startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'start')
-        if startthreadsafety is None:
-            return
-        finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'finish')
-        # record that the function will be intercepted
-        if (self.featureExtraProtect != None):
-            self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
-        self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
-        if (self.featureExtraProtect != None):
-            self.intercepts += [ '#endif' ]
-
-        OutputGenerator.genCmd(self, cmdinfo, name, alias)
-        #
-        decls = self.makeCDecls(cmdinfo.elem)
-        self.appendSection('command', '')
-        self.appendSection('command', decls[0][:-1])
-        self.appendSection('command', '{')
-        # setup common to call wrappers
-        # first parameter is always dispatchable
-        dispatchable_type = cmdinfo.elem.find('param/type').text
-        dispatchable_name = cmdinfo.elem.find('param/name').text
-        self.appendSection('command', '    dispatch_key key = get_dispatch_key('+dispatchable_name+');')
-        self.appendSection('command', '    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);')
-        if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]:
-            self.appendSection('command', '    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;')
-        else:
-            self.appendSection('command', '    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;')
-        # Declare result variable, if any.
-        resulttype = cmdinfo.elem.find('proto/type')
-        if (resulttype != None and resulttype.text == 'void'):
-          resulttype = None
-        if (resulttype != None):
-            self.appendSection('command', '    ' + resulttype.text + ' result;')
-            assignresult = 'result = '
-        else:
-            assignresult = ''
-
-        self.appendSection('command', '    bool threadChecks = startMultiThread();')
-        self.appendSection('command', '    if (threadChecks) {')
-        self.appendSection('command', "    "+"\n    ".join(str(startthreadsafety).rstrip().split("\n")))
-        self.appendSection('command', '    }')
-        params = cmdinfo.elem.findall('param/name')
-        paramstext = ','.join([str(param.text) for param in params])
-        API = cmdinfo.elem.attrib.get('name').replace('vk','pTable->',1)
-        self.appendSection('command', '    ' + assignresult + API + '(' + paramstext + ');')
-        self.appendSection('command', '    if (threadChecks) {')
-        self.appendSection('command', "    "+"\n    ".join(str(finishthreadsafety).rstrip().split("\n")))
-        self.appendSection('command', '    } else {')
-        self.appendSection('command', '        finishMultiThread();')
-        self.appendSection('command', '    }')
-        # Return result variable, if any.
-        if (resulttype != None):
-            self.appendSection('command', '    return result;')
-        self.appendSection('command', '}')
-    #
-    # override makeProtoName to drop the "vk" prefix
-    def makeProtoName(self, name, tail):
-        return self.genOpts.apientry + name[2:] + tail
diff --git a/scripts/unique_objects_generator.py b/scripts/unique_objects_generator.py
deleted file mode 100644
index d5d40f8..0000000
--- a/scripts/unique_objects_generator.py
+++ /dev/null
@@ -1,933 +0,0 @@
-#!/usr/bin/python3 -i
-#
-# Copyright (c) 2015-2016 The Khronos Group Inc.
-# Copyright (c) 2015-2016 Valve Corporation
-# Copyright (c) 2015-2016 LunarG, Inc.
-# Copyright (c) 2015-2016 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Author: Tobin Ehlis <tobine@google.com>
-# Author: Mark Lobodzinski <mark@lunarg.com>
-
-import os,re,sys
-import xml.etree.ElementTree as etree
-from generator import *
-from collections import namedtuple
-from common_codegen import *
-
-# UniqueObjectsGeneratorOptions - subclass of GeneratorOptions.
-#
-# Adds options used by UniqueObjectsOutputGenerator objects during
-# unique objects layer generation.
-#
-# Additional members
-#   prefixText - list of strings to prefix generated header with
-#     (usually a copyright statement + calling convention macros).
-#   protectFile - True if multiple inclusion protection should be
-#     generated (based on the filename) around the entire header.
-#   protectFeature - True if #ifndef..#endif protection should be
-#     generated around a feature interface in the header file.
-#   genFuncPointers - True if function pointer typedefs should be
-#     generated
-#   protectProto - If conditional protection should be generated
-#     around prototype declarations, set to either '#ifdef'
-#     to require opt-in (#ifdef protectProtoStr) or '#ifndef'
-#     to require opt-out (#ifndef protectProtoStr). Otherwise
-#     set to None.
-#   protectProtoStr - #ifdef/#ifndef symbol to use around prototype
-#     declarations, if protectProto is set
-#   apicall - string to use for the function declaration prefix,
-#     such as APICALL on Windows.
-#   apientry - string to use for the calling convention macro,
-#     in typedefs, such as APIENTRY.
-#   apientryp - string to use for the calling convention macro
-#     in function pointer typedefs, such as APIENTRYP.
-#   indentFuncProto - True if prototype declarations should put each
-#     parameter on a separate line
-#   indentFuncPointer - True if typedefed function pointers should put each
-#     parameter on a separate line
-#   alignFuncParam - if nonzero and parameters are being put on a
-#     separate line, align parameter names at the specified column
-class UniqueObjectsGeneratorOptions(GeneratorOptions):
-    def __init__(self,
-                 filename = None,
-                 directory = '.',
-                 apiname = None,
-                 profile = None,
-                 versions = '.*',
-                 emitversions = '.*',
-                 defaultExtensions = None,
-                 addExtensions = None,
-                 removeExtensions = None,
-                 emitExtensions = None,
-                 sortProcedure = regSortFeatures,
-                 prefixText = "",
-                 genFuncPointers = True,
-                 protectFile = True,
-                 protectFeature = True,
-                 apicall = '',
-                 apientry = '',
-                 apientryp = '',
-                 indentFuncProto = True,
-                 indentFuncPointer = False,
-                 alignFuncParam = 0,
-                 expandEnumerants = True):
-        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
-                                  versions, emitversions, defaultExtensions,
-                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
-        self.prefixText      = prefixText
-        self.genFuncPointers = genFuncPointers
-        self.protectFile     = protectFile
-        self.protectFeature  = protectFeature
-        self.apicall         = apicall
-        self.apientry        = apientry
-        self.apientryp       = apientryp
-        self.indentFuncProto = indentFuncProto
-        self.indentFuncPointer = indentFuncPointer
-        self.alignFuncParam   = alignFuncParam
-        self.expandEnumerants = expandEnumerants
-
-
-# UniqueObjectsOutputGenerator - subclass of OutputGenerator.
-# Generates unique objects layer non-dispatchable handle-wrapping code.
-#
-# ---- methods ----
-# UniqueObjectsOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state.
-# ---- methods overriding base class ----
-# beginFile(genOpts)
-# endFile()
-# beginFeature(interface, emit)
-# endFeature()
-# genCmd(cmdinfo)
-# genStruct()
-# genType()
-class UniqueObjectsOutputGenerator(OutputGenerator):
-    """Generate UniqueObjects code based on XML element attributes"""
-    # This is an ordered list of sections in the header file.
-    ALL_SECTIONS = ['command']
-    def __init__(self,
-                 errFile = sys.stderr,
-                 warnFile = sys.stderr,
-                 diagFile = sys.stdout):
-        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
-        self.INDENT_SPACES = 4
-        self.intercepts = []
-        self.instance_extensions = []
-        self.device_extensions = []
-        # Commands which are not autogenerated but still intercepted
-        self.no_autogen_list = [
-            'vkGetDeviceProcAddr',
-            'vkGetInstanceProcAddr',
-            'vkCreateInstance',
-            'vkDestroyInstance',
-            'vkCreateDevice',
-            'vkDestroyDevice',
-            'vkCreateComputePipelines',
-            'vkCreateGraphicsPipelines',
-            'vkCreateSwapchainKHR',
-            'vkCreateSharedSwapchainsKHR',
-            'vkGetSwapchainImagesKHR',
-            'vkDestroySwapchainKHR',
-            'vkQueuePresentKHR',
-            'vkEnumerateInstanceLayerProperties',
-            'vkEnumerateDeviceLayerProperties',
-            'vkEnumerateInstanceExtensionProperties',
-            'vkCreateDescriptorUpdateTemplate',
-            'vkCreateDescriptorUpdateTemplateKHR',
-            'vkDestroyDescriptorUpdateTemplate',
-            'vkDestroyDescriptorUpdateTemplateKHR',
-            'vkUpdateDescriptorSetWithTemplate',
-            'vkUpdateDescriptorSetWithTemplateKHR',
-            'vkCmdPushDescriptorSetWithTemplateKHR',
-            'vkDebugMarkerSetObjectTagEXT',
-            'vkDebugMarkerSetObjectNameEXT',
-            'vkCreateRenderPass',
-            'vkCreateRenderPass2KHR',
-            'vkDestroyRenderPass',
-            'vkSetDebugUtilsObjectNameEXT',
-            'vkSetDebugUtilsObjectTagEXT',
-            'vkGetPhysicalDeviceDisplayPropertiesKHR',
-            'vkGetPhysicalDeviceDisplayProperties2KHR',
-            'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
-            'vkGetPhysicalDeviceDisplayPlaneProperties2KHR',
-            'vkGetDisplayPlaneSupportedDisplaysKHR',
-            'vkGetDisplayModePropertiesKHR',
-            'vkGetDisplayModeProperties2KHR',
-            'vkCreateDebugUtilsMessengerEXT',
-            'vkDestroyDebugUtilsMessengerEXT',
-            'vkSubmitDebugUtilsMessageEXT',
-            'vkCreateDebugReportCallbackEXT',
-            'vkDestroyDebugReportCallbackEXT',
-            'vkDebugReportMessageEXT',
-            ]
-        self.headerVersion = None
-        # Internal state - accumulators for different inner block text
-        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
-
-        self.cmdMembers = []
-        self.cmd_feature_protect = []  # Save ifdef's for each command
-        self.cmd_info_data = []        # Save the cmdinfo data for wrapping the handles when processing is complete
-        self.structMembers = []        # List of StructMemberData records for all Vulkan structs
-        self.extension_structs = []    # List of all structs or sister-structs containing handles
-                                       # A sister-struct may contain no handles but shares a structextends attribute with one that does
-        self.structTypes = dict()      # Map of Vulkan struct typename to required VkStructureType
-        self.struct_member_dict = dict()
-        # Named tuples to store struct and command data
-        self.StructType = namedtuple('StructType', ['name', 'value'])
-        self.CmdMemberData = namedtuple('CmdMemberData', ['name', 'members'])
-        self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo'])
-        self.CmdExtraProtect = namedtuple('CmdExtraProtect', ['name', 'extra_protect'])
-
-        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy', 'feature_protect'])
-        self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
-    #
-    def incIndent(self, indent):
-        inc = ' ' * self.INDENT_SPACES
-        if indent:
-            return indent + inc
-        return inc
-    #
-    def decIndent(self, indent):
-        if indent and (len(indent) > self.INDENT_SPACES):
-            return indent[:-self.INDENT_SPACES]
-        return ''
-    #
-    # Override makeProtoName to drop the "vk" prefix
-    def makeProtoName(self, name, tail):
-        return self.genOpts.apientry + name[2:] + tail
-    #
-    # Check if the parameter passed in is a pointer to an array
-    def paramIsArray(self, param):
-        return param.attrib.get('len') is not None
-    #
-    def beginFile(self, genOpts):
-        OutputGenerator.beginFile(self, genOpts)
-        # User-supplied prefix text, if any (list of strings)
-        if (genOpts.prefixText):
-            for s in genOpts.prefixText:
-                write(s, file=self.outFile)
-        # Namespace
-        self.newline()
-        write('namespace unique_objects {', file = self.outFile)
-    # Now that the data is all collected and complete, generate and output the wrapping/unwrapping routines
-    def endFile(self):
-
-        self.struct_member_dict = dict(self.structMembers)
-
-        # Generate the list of APIs that might need to handle wrapped extension structs
-        self.GenerateCommandWrapExtensionList()
-        # Write out wrapping/unwrapping functions
-        self.WrapCommands()
-        # Build and write out pNext processing function
-        extension_proc = self.build_extension_processing_func()
-        self.newline()
-        write('// Unique Objects pNext extension handling function', file=self.outFile)
-        write('%s' % extension_proc, file=self.outFile)
-
-        # Actually write the interface to the output file.
-        if (self.emit):
-            self.newline()
-            if (self.featureExtraProtect != None):
-                write('#ifdef', self.featureExtraProtect, file=self.outFile)
-            # Write the unique_objects code to the file
-            if (self.sections['command']):
-                write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
-            if (self.featureExtraProtect != None):
-                write('\n#endif //', self.featureExtraProtect, file=self.outFile)
-            else:
-                self.newline()
-
-        # Record intercepted procedures
-        write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
-        write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
-        write('\n'.join(self.intercepts), file=self.outFile)
-        write('};\n', file=self.outFile)
-        self.newline()
-        write('} // namespace unique_objects', file=self.outFile)
-        # Finish processing in superclass
-        OutputGenerator.endFile(self)
-    #
-    def beginFeature(self, interface, emit):
-        # Start processing in superclass
-        OutputGenerator.beginFeature(self, interface, emit)
-        self.headerVersion = None
-        self.featureExtraProtect = GetFeatureProtect(interface)
-        if self.featureName != 'VK_VERSION_1_0' and self.featureName != 'VK_VERSION_1_1':
-            white_list_entry = []
-            if (self.featureExtraProtect != None):
-                white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ]
-            white_list_entry += [ '"%s"' % self.featureName ]
-            if (self.featureExtraProtect != None):
-                white_list_entry += [ '#endif' ]
-            featureType = interface.get('type')
-            if featureType == 'instance':
-                self.instance_extensions += white_list_entry
-            elif featureType == 'device':
-                self.device_extensions += white_list_entry
-    #
-    def endFeature(self):
-        # Finish processing in superclass
-        OutputGenerator.endFeature(self)
-    #
-    def genType(self, typeinfo, name, alias):
-        OutputGenerator.genType(self, typeinfo, name, alias)
-        typeElem = typeinfo.elem
-        # If the type is a struct type, traverse the imbedded <member> tags generating a structure.
-        # Otherwise, emit the tag text.
-        category = typeElem.get('category')
-        if (category == 'struct' or category == 'union'):
-            self.genStruct(typeinfo, name, alias)
-    #
-    # Append a definition to the specified section
-    def appendSection(self, section, text):
-        # self.sections[section].append('SECTION: ' + section + '\n')
-        self.sections[section].append(text)
-    #
-    # Check if the parameter passed in is a pointer
-    def paramIsPointer(self, param):
-        ispointer = False
-        for elem in param:
-            if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
-                ispointer = True
-        return ispointer
-    #
-    # Get the category of a type
-    def getTypeCategory(self, typename):
-        types = self.registry.tree.findall("types/type")
-        for elem in types:
-            if (elem.find("name") is not None and elem.find('name').text == typename) or elem.attrib.get('name') == typename:
-                return elem.attrib.get('category')
-    #
-    # Check if a parent object is dispatchable or not
-    def isHandleTypeNonDispatchable(self, handletype):
-        handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
-        if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
-            return True
-        else:
-            return False
-    #
-    # Retrieve the type and name for a parameter
-    def getTypeNameTuple(self, param):
-        type = ''
-        name = ''
-        for elem in param:
-            if elem.tag == 'type':
-                type = noneStr(elem.text)
-            elif elem.tag == 'name':
-                name = noneStr(elem.text)
-        return (type, name)
-    #
-    # Retrieve the value of the len tag
-    def getLen(self, param):
-        result = None
-        len = param.attrib.get('len')
-        if len and len != 'null-terminated':
-            # For string arrays, 'len' can look like 'count,null-terminated', indicating that we
-            # have a null terminated array of strings.  We strip the null-terminated from the
-            # 'len' field and only return the parameter specifying the string count
-            if 'null-terminated' in len:
-                result = len.split(',')[0]
-            else:
-                result = len
-            # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol
-            result = str(result).replace('::', '->')
-        return result
-    #
-    # Generate a VkStructureType based on a structure typename
-    def genVkStructureType(self, typename):
-        # Add underscore between lowercase then uppercase
-        value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
-        # Change to uppercase
-        value = value.upper()
-        # Add STRUCTURE_TYPE_
-        return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value)
-    #
-    # Struct parameter check generation.
-    # This is a special case of the <type> tag where the contents are interpreted as a set of
-    # <member> tags instead of freeform C type declarations. The <member> tags are just like
-    # <param> tags - they are a declaration of a struct or union member. Only simple member
-    # declarations are supported (no nested structs etc.)
-    def genStruct(self, typeinfo, typeName, alias):
-        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
-        members = typeinfo.elem.findall('.//member')
-        # Iterate over members once to get length parameters for arrays
-        lens = set()
-        for member in members:
-            len = self.getLen(member)
-            if len:
-                lens.add(len)
-        # Generate member info
-        membersInfo = []
-        for member in members:
-            # Get the member's type and name
-            info = self.getTypeNameTuple(member)
-            type = info[0]
-            name = info[1]
-            cdecl = self.makeCParamDecl(member, 0)
-            # Process VkStructureType
-            if type == 'VkStructureType':
-                # Extract the required struct type value from the comments
-                # embedded in the original text defining the 'typeinfo' element
-                rawXml = etree.tostring(typeinfo.elem).decode('ascii')
-                result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml)
-                if result:
-                    value = result.group(0)
-                else:
-                    value = self.genVkStructureType(typeName)
-                # Store the required type value
-                self.structTypes[typeName] = self.StructType(name=name, value=value)
-            # Store pointer/array/string info
-            extstructs = self.registry.validextensionstructs[typeName] if name == 'pNext' else None
-            membersInfo.append(self.CommandParam(type=type,
-                                                 name=name,
-                                                 ispointer=self.paramIsPointer(member),
-                                                 isconst=True if 'const' in cdecl else False,
-                                                 iscount=True if name in lens else False,
-                                                 len=self.getLen(member),
-                                                 extstructs=extstructs,
-                                                 cdecl=cdecl,
-                                                 islocal=False,
-                                                 iscreate=False,
-                                                 isdestroy=False,
-                                                 feature_protect=self.featureExtraProtect))
-        self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
-
-    #
-    # Insert a lock_guard line
-    def lock_guard(self, indent):
-        return '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % indent
-    #
-    # Determine if a struct has an NDO as a member or an embedded member
-    def struct_contains_ndo(self, struct_item):
-        struct_member_dict = dict(self.structMembers)
-        struct_members = struct_member_dict[struct_item]
-
-        for member in struct_members:
-            if self.isHandleTypeNonDispatchable(member.type):
-                return True
-            elif member.type in struct_member_dict:
-                if self.struct_contains_ndo(member.type) == True:
-                    return True
-        return False
-    #
-    # Return list of struct members which contain, or which sub-structures contain
-    # an NDO in a given list of parameters or members
-    def getParmeterStructsWithNdos(self, item_list):
-        struct_list = set()
-        for item in item_list:
-            paramtype = item.find('type')
-            typecategory = self.getTypeCategory(paramtype.text)
-            if typecategory == 'struct':
-                if self.struct_contains_ndo(paramtype.text) == True:
-                    struct_list.add(item)
-        return struct_list
-    #
-    # Return list of non-dispatchable objects from a given list of parameters or members
-    def getNdosInParameterList(self, item_list, create_func):
-        ndo_list = set()
-        if create_func == True:
-            member_list = item_list[0:-1]
-        else:
-            member_list = item_list
-        for item in member_list:
-            if self.isHandleTypeNonDispatchable(paramtype.text):
-                ndo_list.add(item)
-        return ndo_list
-    #
-    # Construct list of extension structs containing handles, or extension structs that share a structextends attribute
-    # WITH an extension struct containing handles. All extension structs in any pNext chain will have to be copied.
-    # TODO: make this recursive -- structs buried three or more levels deep are not searched for extensions
-    def GenerateCommandWrapExtensionList(self):
-        for struct in self.structMembers:
-            if (len(struct.members) > 1) and struct.members[1].extstructs is not None:
-                found = False;
-                for item in struct.members[1].extstructs:
-                    if item != '' and self.struct_contains_ndo(item) == True:
-                        found = True
-                if found == True:
-                    for item in struct.members[1].extstructs:
-                        if item != '' and item not in self.extension_structs:
-                            self.extension_structs.append(item)
-    #
-    # Returns True if a struct may have a pNext chain containing an NDO
-    def StructWithExtensions(self, struct_type):
-        if struct_type in self.struct_member_dict:
-            param_info = self.struct_member_dict[struct_type]
-            if (len(param_info) > 1) and param_info[1].extstructs is not None:
-                for item in param_info[1].extstructs:
-                    if item in self.extension_structs:
-                        return True
-        return False
-    #
-    # Generate pNext handling function
-    def build_extension_processing_func(self):
-        # Construct helper functions to build and free pNext extension chains
-        pnext_proc = ''
-        pnext_proc += 'void *CreateUnwrappedExtensionStructs(const void *pNext) {\n'
-        pnext_proc += '    void *cur_pnext = const_cast<void *>(pNext);\n'
-        pnext_proc += '    void *head_pnext = NULL;\n'
-        pnext_proc += '    void *prev_ext_struct = NULL;\n'
-        pnext_proc += '    void *cur_ext_struct = NULL;\n\n'
-        pnext_proc += '    while (cur_pnext != NULL) {\n'
-        pnext_proc += '        GenericHeader *header = reinterpret_cast<GenericHeader *>(cur_pnext);\n\n'
-        pnext_proc += '        switch (header->sType) {\n'
-        for item in self.extension_structs:
-            struct_info = self.struct_member_dict[item]
-            if struct_info[0].feature_protect is not None:
-                pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect
-            pnext_proc += '            case %s: {\n' % self.structTypes[item].value
-            pnext_proc += '                    safe_%s *safe_struct = new safe_%s;\n' % (item, item)
-            pnext_proc += '                    safe_struct->initialize(reinterpret_cast<const %s *>(cur_pnext));\n' % item
-            # Generate code to unwrap the handles
-            indent = '                '
-            (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, 'safe_struct->', 0, False, False, False, False)
-            pnext_proc += tmp_pre
-            pnext_proc += '                    cur_ext_struct = reinterpret_cast<void *>(safe_struct);\n'
-            pnext_proc += '                } break;\n'
-            if struct_info[0].feature_protect is not None:
-                pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect
-            pnext_proc += '\n'
-        pnext_proc += '            default:\n'
-        pnext_proc += '                break;\n'
-        pnext_proc += '        }\n\n'
-        pnext_proc += '        // Save pointer to the first structure in the pNext chain\n'
-        pnext_proc += '        head_pnext = (head_pnext ? head_pnext : cur_ext_struct);\n\n'
-        pnext_proc += '        // For any extension structure but the first, link the last struct\'s pNext to the current ext struct\n'
-        pnext_proc += '        if (prev_ext_struct) {\n'
-        pnext_proc += '            (reinterpret_cast<GenericHeader *>(prev_ext_struct))->pNext = cur_ext_struct;\n'
-        pnext_proc += '        }\n'
-        pnext_proc += '        prev_ext_struct = cur_ext_struct;\n\n'
-        pnext_proc += '        // Process the next structure in the chain\n'
-        pnext_proc += '        cur_pnext = const_cast<void *>(header->pNext);\n'
-        pnext_proc += '    }\n'
-        pnext_proc += '    return head_pnext;\n'
-        pnext_proc += '}\n\n'
-        pnext_proc += '// Free a pNext extension chain\n'
-        pnext_proc += 'void FreeUnwrappedExtensionStructs(void *head) {\n'
-        pnext_proc += '    GenericHeader *curr_ptr = reinterpret_cast<GenericHeader *>(head);\n'
-        pnext_proc += '    while (curr_ptr) {\n'
-        pnext_proc += '        GenericHeader *header = curr_ptr;\n'
-        pnext_proc += '        curr_ptr = reinterpret_cast<GenericHeader *>(header->pNext);\n\n'
-        pnext_proc += '        switch (header->sType) {\n';
-        for item in self.extension_structs:
-            struct_info = self.struct_member_dict[item]
-            if struct_info[0].feature_protect is not None:
-                pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect
-            pnext_proc += '            case %s:\n' % self.structTypes[item].value
-            pnext_proc += '                delete reinterpret_cast<safe_%s *>(header);\n' % item
-            pnext_proc += '                break;\n'
-            if struct_info[0].feature_protect is not None:
-                pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect
-            pnext_proc += '\n'
-        pnext_proc += '            default:\n'
-        pnext_proc += '                assert(0);\n'
-        pnext_proc += '        }\n'
-        pnext_proc += '    }\n'
-        pnext_proc += '}\n'
-        return pnext_proc
-
-    #
-    # Generate source for creating a non-dispatchable object
-    def generate_create_ndo_code(self, indent, proto, params, cmd_info):
-        create_ndo_code = ''
-        handle_type = params[-1].find('type')
-        if self.isHandleTypeNonDispatchable(handle_type.text):
-            # Check for special case where multiple handles are returned
-            ndo_array = False
-            if cmd_info[-1].len is not None:
-                ndo_array = True;
-            handle_name = params[-1].find('name')
-            create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
-            indent = self.incIndent(indent)
-            create_ndo_code += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
-            ndo_dest = '*%s' % handle_name.text
-            if ndo_array == True:
-                create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len)
-                indent = self.incIndent(indent)
-                ndo_dest = '%s[index0]' % cmd_info[-1].name
-            create_ndo_code += '%s%s = WrapNew(%s);\n' % (indent, ndo_dest, ndo_dest)
-            if ndo_array == True:
-                indent = self.decIndent(indent)
-                create_ndo_code += '%s}\n' % indent
-            indent = self.decIndent(indent)
-            create_ndo_code += '%s}\n' % (indent)
-        return create_ndo_code
-    #
-    # Generate source for destroying a non-dispatchable object
-    def generate_destroy_ndo_code(self, indent, proto, cmd_info):
-        destroy_ndo_code = ''
-        ndo_array = False
-        if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free']]:
-            # Check for special case where multiple handles are returned
-            if cmd_info[-1].len is not None:
-                ndo_array = True;
-                param = -1
-            else:
-                param = -2
-            if self.isHandleTypeNonDispatchable(cmd_info[param].type) == True:
-                if ndo_array == True:
-                    # This API is freeing an array of handles.  Remove them from the unique_id map.
-                    destroy_ndo_code += '%sif ((VK_SUCCESS == result) && (%s)) {\n' % (indent, cmd_info[param].name)
-                    indent = self.incIndent(indent)
-                    destroy_ndo_code += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % (indent)
-                    destroy_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[param].len)
-                    indent = self.incIndent(indent)
-                    destroy_ndo_code += '%s%s handle = %s[index0];\n' % (indent, cmd_info[param].type, cmd_info[param].name)
-                    destroy_ndo_code += '%suint64_t unique_id = reinterpret_cast<uint64_t &>(handle);\n' % (indent)
-                    destroy_ndo_code += '%sunique_id_mapping.erase(unique_id);\n' % (indent)
-                    indent = self.decIndent(indent);
-                    destroy_ndo_code += '%s}\n' % indent
-                    indent = self.decIndent(indent);
-                    destroy_ndo_code += '%s}\n' % indent
-                else:
-                    # Remove a single handle from the map
-                    destroy_ndo_code += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % (indent)
-                    destroy_ndo_code += '%suint64_t %s_id = reinterpret_cast<uint64_t &>(%s);\n' % (indent, cmd_info[param].name, cmd_info[param].name)
-                    destroy_ndo_code += '%s%s = (%s)unique_id_mapping[%s_id];\n' % (indent, cmd_info[param].name, cmd_info[param].type, cmd_info[param].name)
-                    destroy_ndo_code += '%sunique_id_mapping.erase(%s_id);\n' % (indent, cmd_info[param].name)
-                    destroy_ndo_code += '%slock.unlock();\n' % (indent)
-        return ndo_array, destroy_ndo_code
-
-    #
-    # Clean up local declarations
-    def cleanUpLocalDeclarations(self, indent, prefix, name, len, index, process_pnext):
-        cleanup = '%sif (local_%s%s) {\n' % (indent, prefix, name)
-        if len is not None:
-            if process_pnext:
-                cleanup += '%s    for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, len, index)
-                cleanup += '%s        FreeUnwrappedExtensionStructs(const_cast<void *>(local_%s%s[%s].pNext));\n' % (indent, prefix, name, index)
-                cleanup += '%s    }\n' % indent
-            cleanup += '%s    delete[] local_%s%s;\n' % (indent, prefix, name)
-        else:
-            if process_pnext:
-                cleanup += '%s    FreeUnwrappedExtensionStructs(const_cast<void *>(local_%s%s->pNext));\n' % (indent, prefix, name)
-            cleanup += '%s    delete local_%s%s;\n' % (indent, prefix, name)
-        cleanup += "%s}\n" % (indent)
-        return cleanup
-    #
-    # Output UO code for a single NDO (ndo_count is NULL) or a counted list of NDOs
-    def outputNDOs(self, ndo_type, ndo_name, ndo_count, prefix, index, indent, destroy_func, destroy_array, top_level):
-        decl_code = ''
-        pre_call_code = ''
-        post_call_code = ''
-        if ndo_count is not None:
-            if top_level == True:
-                decl_code += '%s%s *local_%s%s = NULL;\n' % (indent, ndo_type, prefix, ndo_name)
-            pre_call_code += '%s    if (%s%s) {\n' % (indent, prefix, ndo_name)
-            indent = self.incIndent(indent)
-            if top_level == True:
-                pre_call_code += '%s    local_%s%s = new %s[%s];\n' % (indent, prefix, ndo_name, ndo_type, ndo_count)
-                pre_call_code += '%s    for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index)
-                indent = self.incIndent(indent)
-                pre_call_code += '%s    local_%s%s[%s] = Unwrap(%s[%s]);\n' % (indent, prefix, ndo_name, index, ndo_name, index)
-            else:
-                pre_call_code += '%s    for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index)
-                indent = self.incIndent(indent)
-                pre_call_code += '%s    %s%s[%s] = Unwrap(%s%s[%s]);\n' % (indent, prefix, ndo_name, index, prefix, ndo_name, index)
-            indent = self.decIndent(indent)
-            pre_call_code += '%s    }\n' % indent
-            indent = self.decIndent(indent)
-            pre_call_code += '%s    }\n' % indent
-            if top_level == True:
-                post_call_code += '%sif (local_%s%s)\n' % (indent, prefix, ndo_name)
-                indent = self.incIndent(indent)
-                post_call_code += '%sdelete[] local_%s;\n' % (indent, ndo_name)
-        else:
-            if top_level == True:
-                if (destroy_func == False) or (destroy_array == True):
-                    pre_call_code += '%s    %s = Unwrap(%s);\n' % (indent, ndo_name, ndo_name)
-            else:
-                # Make temp copy of this var with the 'local' removed. It may be better to not pass in 'local_'
-                # as part of the string and explicitly print it
-                fix = str(prefix).strip('local_');
-                pre_call_code += '%s    if (%s%s) {\n' % (indent, fix, ndo_name)
-                indent = self.incIndent(indent)
-                pre_call_code += '%s    %s%s = Unwrap(%s%s);\n' % (indent, prefix, ndo_name, fix, ndo_name)
-                indent = self.decIndent(indent)
-                pre_call_code += '%s    }\n' % indent
-        return decl_code, pre_call_code, post_call_code
-    #
-    # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
-    # create_func means that this is API creates or allocates NDOs
-    # destroy_func indicates that this API destroys or frees NDOs
-    # destroy_array means that the destroy_func operated on an array of NDOs
-    def uniquify_members(self, members, indent, prefix, array_index, create_func, destroy_func, destroy_array, first_level_param):
-        decls = ''
-        pre_code = ''
-        post_code = ''
-        index = 'index%s' % str(array_index)
-        array_index += 1
-        # Process any NDOs in this structure and recurse for any sub-structs in this struct
-        for member in members:
-            process_pnext = self.StructWithExtensions(member.type)
-            # Handle NDOs
-            if self.isHandleTypeNonDispatchable(member.type) == True:
-                count_name = member.len
-                if (count_name is not None):
-                    if first_level_param == False:
-                        count_name = '%s%s' % (prefix, member.len)
-
-                if (first_level_param == False) or (create_func == False) or (not '*' in member.cdecl):
-                    (tmp_decl, tmp_pre, tmp_post) = self.outputNDOs(member.type, member.name, count_name, prefix, index, indent, destroy_func, destroy_array, first_level_param)
-                    decls += tmp_decl
-                    pre_code += tmp_pre
-                    post_code += tmp_post
-            # Handle Structs that contain NDOs at some level
-            elif member.type in self.struct_member_dict:
-                # Structs at first level will have an NDO, OR, we need a safe_struct for the pnext chain
-                if self.struct_contains_ndo(member.type) == True or process_pnext:
-                    struct_info = self.struct_member_dict[member.type]
-                    # TODO (jbolz): Can this use paramIsPointer?
-                    ispointer = '*' in member.cdecl;
-                    # Struct Array
-                    if member.len is not None:
-                        # Update struct prefix
-                        if first_level_param == True:
-                            new_prefix = 'local_%s' % member.name
-                            # Declare safe_VarType for struct
-                            decls += '%ssafe_%s *%s = NULL;\n' % (indent, member.type, new_prefix)
-                        else:
-                            new_prefix = '%s%s' % (prefix, member.name)
-                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
-                        indent = self.incIndent(indent)
-                        if first_level_param == True:
-                            pre_code += '%s    %s = new safe_%s[%s];\n' % (indent, new_prefix, member.type, member.len)
-                        pre_code += '%s    for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index)
-                        indent = self.incIndent(indent)
-                        if first_level_param == True:
-                            pre_code += '%s    %s[%s].initialize(&%s[%s]);\n' % (indent, new_prefix, index, member.name, index)
-                            if process_pnext:
-                                pre_code += '%s    %s[%s].pNext = CreateUnwrappedExtensionStructs(%s[%s].pNext);\n' % (indent, new_prefix, index, new_prefix, index)
-                        local_prefix = '%s[%s].' % (new_prefix, index)
-                        # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, local_prefix, array_index, create_func, destroy_func, destroy_array, False)
-                        decls += tmp_decl
-                        pre_code += tmp_pre
-                        post_code += tmp_post
-                        indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
-                        indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
-                        if first_level_param == True:
-                            post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index, process_pnext)
-                    # Single Struct
-                    elif ispointer:
-                        # Update struct prefix
-                        if first_level_param == True:
-                            new_prefix = 'local_%s->' % member.name
-                            decls += '%ssafe_%s *local_%s%s = NULL;\n' % (indent, member.type, prefix, member.name)
-                        else:
-                            new_prefix = '%s%s->' % (prefix, member.name)
-                        # Declare safe_VarType for struct
-                        pre_code += '%s    if (%s%s) {\n' % (indent, prefix, member.name)
-                        indent = self.incIndent(indent)
-                        if first_level_param == True:
-                            pre_code += '%s    local_%s%s = new safe_%s(%s);\n' % (indent, prefix, member.name, member.type, member.name)
-                        # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False)
-                        decls += tmp_decl
-                        pre_code += tmp_pre
-                        post_code += tmp_post
-                        if process_pnext:
-                            pre_code += '%s    local_%s%s->pNext = CreateUnwrappedExtensionStructs(local_%s%s->pNext);\n' % (indent, prefix, member.name, prefix, member.name)
-                        indent = self.decIndent(indent)
-                        pre_code += '%s    }\n' % indent
-                        if first_level_param == True:
-                            post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index, process_pnext)
-                    else:
-                        # Update struct prefix
-                        if first_level_param == True:
-                            sys.exit(1)
-                        else:
-                            new_prefix = '%s%s.' % (prefix, member.name)
-                        # Process sub-structs in this struct
-                        (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False)
-                        decls += tmp_decl
-                        pre_code += tmp_pre
-                        post_code += tmp_post
-                        if process_pnext:
-                            pre_code += '%s    local_%s%s.pNext = CreateUnwrappedExtensionStructs(local_%s%s.pNext);\n' % (indent, prefix, member.name, prefix, member.name)
-        return decls, pre_code, post_code
-    #
-    # For a particular API, generate the non-dispatchable-object wrapping/unwrapping code
-    def generate_wrapping_code(self, cmd):
-        indent = '    '
-        proto = cmd.find('proto/name')
-        params = cmd.findall('param')
-
-        if proto.text is not None:
-            cmd_member_dict = dict(self.cmdMembers)
-            cmd_info = cmd_member_dict[proto.text]
-            # Handle ndo create/allocate operations
-            if cmd_info[0].iscreate:
-                create_ndo_code = self.generate_create_ndo_code(indent, proto, params, cmd_info)
-            else:
-                create_ndo_code = ''
-            # Handle ndo destroy/free operations
-            if cmd_info[0].isdestroy:
-                (destroy_array, destroy_ndo_code) = self.generate_destroy_ndo_code(indent, proto, cmd_info)
-            else:
-                destroy_array = False
-                destroy_ndo_code = ''
-            paramdecl = ''
-            param_pre_code = ''
-            param_post_code = ''
-            create_func = True if create_ndo_code else False
-            destroy_func = True if destroy_ndo_code else False
-            (paramdecl, param_pre_code, param_post_code) = self.uniquify_members(cmd_info, indent, '', 0, create_func, destroy_func, destroy_array, True)
-            param_post_code += create_ndo_code
-            if destroy_ndo_code:
-                if destroy_array == True:
-                    param_post_code += destroy_ndo_code
-                else:
-                    param_pre_code += destroy_ndo_code
-            if param_pre_code:
-                if (not destroy_func) or (destroy_array):
-                    param_pre_code = '%s{\n%s%s%s%s}\n' % ('    ', indent, self.lock_guard(indent), param_pre_code, indent)
-        return paramdecl, param_pre_code, param_post_code
-    #
-    # Capture command parameter info needed to wrap NDOs as well as handling some boilerplate code
-    def genCmd(self, cmdinfo, cmdname, alias):
-
-        # Add struct-member type information to command parameter information
-        OutputGenerator.genCmd(self, cmdinfo, cmdname, alias)
-        members = cmdinfo.elem.findall('.//param')
-        # Iterate over members once to get length parameters for arrays
-        lens = set()
-        for member in members:
-            len = self.getLen(member)
-            if len:
-                lens.add(len)
-        struct_member_dict = dict(self.structMembers)
-        # Generate member info
-        membersInfo = []
-        constains_extension_structs = False
-        for member in members:
-            # Get type and name of member
-            info = self.getTypeNameTuple(member)
-            type = info[0]
-            name = info[1]
-            cdecl = self.makeCParamDecl(member, 0)
-            # Check for parameter name in lens set
-            iscount = True if name in lens else False
-            len = self.getLen(member)
-            isconst = True if 'const' in cdecl else False
-            ispointer = self.paramIsPointer(member)
-            # Mark param as local if it is an array of NDOs
-            islocal = False;
-            if self.isHandleTypeNonDispatchable(type) == True:
-                if (len is not None) and (isconst == True):
-                    islocal = True
-            # Or if it's a struct that contains an NDO
-            elif type in struct_member_dict:
-                if self.struct_contains_ndo(type) == True:
-                    islocal = True
-            isdestroy = True if True in [destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free']] else False
-            iscreate = True if True in [create_txt in cmdname for create_txt in ['Create', 'Allocate', 'GetRandROutputDisplayEXT', 'RegisterDeviceEvent', 'RegisterDisplayEvent']] else False
-            extstructs = self.registry.validextensionstructs[type] if name == 'pNext' else None
-            membersInfo.append(self.CommandParam(type=type,
-                                                 name=name,
-                                                 ispointer=ispointer,
-                                                 isconst=isconst,
-                                                 iscount=iscount,
-                                                 len=len,
-                                                 extstructs=extstructs,
-                                                 cdecl=cdecl,
-                                                 islocal=islocal,
-                                                 iscreate=iscreate,
-                                                 isdestroy=isdestroy,
-                                                 feature_protect=self.featureExtraProtect))
-        self.cmdMembers.append(self.CmdMemberData(name=cmdname, members=membersInfo))
-        self.cmd_info_data.append(self.CmdInfoData(name=cmdname, cmdinfo=cmdinfo))
-        self.cmd_feature_protect.append(self.CmdExtraProtect(name=cmdname, extra_protect=self.featureExtraProtect))
-    #
-    # Create code to wrap NDOs as well as handling some boilerplate code
-    def WrapCommands(self):
-        cmd_member_dict = dict(self.cmdMembers)
-        cmd_info_dict = dict(self.cmd_info_data)
-        cmd_protect_dict = dict(self.cmd_feature_protect)
-
-        for api_call in self.cmdMembers:
-            cmdname = api_call.name
-            cmdinfo = cmd_info_dict[api_call.name]
-            if cmdname in self.no_autogen_list:
-                decls = self.makeCDecls(cmdinfo.elem)
-                self.appendSection('command', '')
-                self.appendSection('command', '// Declare only')
-                self.appendSection('command', decls[0])
-                self.intercepts += [ '    {"%s", (void *)%s},' % (cmdname,cmdname[2:]) ]
-                continue
-            # Generate NDO wrapping/unwrapping code for all parameters
-            (api_decls, api_pre, api_post) = self.generate_wrapping_code(cmdinfo.elem)
-            # If API doesn't contain an NDO's, don't fool with it
-            if not api_decls and not api_pre and not api_post:
-                continue
-            feature_extra_protect = cmd_protect_dict[api_call.name]
-            if (feature_extra_protect != None):
-                self.appendSection('command', '')
-                self.appendSection('command', '#ifdef '+ feature_extra_protect)
-                self.intercepts += [ '#ifdef %s' % feature_extra_protect ]
-            # Add intercept to procmap
-            self.intercepts += [ '    {"%s", (void*)%s},' % (cmdname,cmdname[2:]) ]
-            decls = self.makeCDecls(cmdinfo.elem)
-            self.appendSection('command', '')
-            self.appendSection('command', decls[0][:-1])
-            self.appendSection('command', '{')
-            # Setup common to call wrappers, first parameter is always dispatchable
-            dispatchable_type = cmdinfo.elem.find('param/type').text
-            dispatchable_name = cmdinfo.elem.find('param/name').text
-            # Generate local instance/pdev/device data lookup
-            if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]:
-                self.appendSection('command', '    instance_layer_data *dev_data = GetLayerDataPtr(get_dispatch_key('+dispatchable_name+'), instance_layer_data_map);')
-            else:
-                self.appendSection('command', '    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key('+dispatchable_name+'), layer_data_map);')
-            # Handle return values, if any
-            resulttype = cmdinfo.elem.find('proto/type')
-            if (resulttype != None and resulttype.text == 'void'):
-              resulttype = None
-            if (resulttype != None):
-                assignresult = resulttype.text + ' result = '
-            else:
-                assignresult = ''
-            # Pre-pend declarations and pre-api-call codegen
-            if api_decls:
-                self.appendSection('command', "\n".join(str(api_decls).rstrip().split("\n")))
-            if api_pre:
-                self.appendSection('command', "\n".join(str(api_pre).rstrip().split("\n")))
-            # Generate the API call itself
-            # Gather the parameter items
-            params = cmdinfo.elem.findall('param/name')
-            # Pull out the text for each of the parameters, separate them by commas in a list
-            paramstext = ', '.join([str(param.text) for param in params])
-            # If any of these paramters has been replaced by a local var, fix up the list
-            params = cmd_member_dict[cmdname]
-            for param in params:
-                if param.islocal == True or self.StructWithExtensions(param.type):
-                    if param.ispointer == True:
-                        paramstext = paramstext.replace(param.name, '(%s %s*)local_%s' % ('const', param.type, param.name))
-                    else:
-                        paramstext = paramstext.replace(param.name, '(%s %s)local_%s' % ('const', param.type, param.name))
-            # Use correct dispatch table
-            API = cmdinfo.elem.attrib.get('name').replace('vk','dev_data->dispatch_table.',1)
-            # Put all this together for the final down-chain call
-            self.appendSection('command', '    ' + assignresult + API + '(' + paramstext + ');')
-            # And add the post-API-call codegen
-            self.appendSection('command', "\n".join(str(api_post).rstrip().split("\n")))
-            # Handle the return result variable, if any
-            if (resulttype != None):
-                self.appendSection('command', '    return result;')
-            self.appendSection('command', '}')
-            if (feature_extra_protect != None):
-                self.appendSection('command', '#endif // '+ feature_extra_protect)
-                self.intercepts += [ '#endif' ]
diff --git a/scripts/update_deps.py b/scripts/update_deps.py
index 119cf70..5d00eb5 100755
--- a/scripts/update_deps.py
+++ b/scripts/update_deps.py
@@ -306,9 +306,9 @@
         self.build_dir = None
         self.install_dir = None
         if json.get('build_dir'):
-            self.build_dir = json['build_dir']
+            self.build_dir = os.path.normpath(json['build_dir'])
         if json.get('install_dir'):
-            self.install_dir = json['install_dir']
+            self.install_dir = os.path.normpath(json['install_dir'])
         self.deps = json['deps'] if ('deps' in json) else []
         self.prebuild = json['prebuild'] if ('prebuild' in json) else []
         self.prebuild_linux = json['prebuild_linux'] if (
@@ -520,6 +520,8 @@
     This information is baked into the CMake files of the home repo and so
     this dictionary is kept with the repo via the json file.
     """
+    def escape(path):
+        return path.replace('\\', '\\\\')
     install_names = GetInstallNames(args)
     with open(filename, 'w') as helper_file:
         for repo in repos:
@@ -527,7 +529,7 @@
                 helper_file.write('set({var} "{dir}" CACHE STRING "" FORCE)\n'
                                   .format(
                                       var=install_names[repo.name],
-                                      dir=repo.install_dir))
+                                      dir=escape(repo.install_dir)))
 
 
 def main():
diff --git a/scripts/vk_validation_stats.py b/scripts/vk_validation_stats.py
index a4619bc..795a0f3 100755
--- a/scripts/vk_validation_stats.py
+++ b/scripts/vk_validation_stats.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Khronos Group Inc.
-# Copyright (c) 2015-2018 Valve Corporation
-# Copyright (c) 2015-2018 LunarG, Inc.
-# Copyright (c) 2015-2018 Google Inc.
+# Copyright (c) 2015-2019 The Khronos Group Inc.
+# Copyright (c) 2015-2019 Valve Corporation
+# Copyright (c) 2015-2019 LunarG, Inc.
+# Copyright (c) 2015-2019 Google Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 #
 # Author: Tobin Ehlis <tobine@google.com>
 # Author: Dave Houlton <daveh@lunarg.com>
+# Author: Shannon McPherson <shannon@lunarg.com>
 
 import argparse
 import os
@@ -28,6 +29,7 @@
 import re
 import csv
 import html
+import time
 from collections import defaultdict
 
 verbose_mode = False
@@ -50,65 +52,67 @@
 'build',
 'dbuild',
 'release',
+'../build/Vulkan-ValidationLayers/'
 ]
 generated_layer_source_files = [
 'parameter_validation.cpp',
 'object_tracker.cpp',
 ]
 layer_source_files = [
+'../layers/buffer_validation.cpp',
 '../layers/core_validation.cpp',
 '../layers/descriptor_sets.cpp',
 '../layers/parameter_validation_utils.cpp',
 '../layers/object_tracker_utils.cpp',
 '../layers/shader_validation.cpp',
-'../layers/buffer_validation.cpp',
+'../layers/stateless_validation.h'
 ]
 
 # This needs to be updated as new extensions roll in
-khr_aliases = { 
-    'VUID-vkBindBufferMemory2KHR-device-parameter'                                        : 'VUID-vkBindBufferMemory2-device-parameter', 
-    'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter'                                    : 'VUID-vkBindBufferMemory2-pBindInfos-parameter', 
-    'VUID-vkBindImageMemory2KHR-device-parameter'                                         : 'VUID-vkBindImageMemory2-device-parameter', 
-    'VUID-vkBindImageMemory2KHR-pBindInfos-parameter'                                     : 'VUID-vkBindImageMemory2-pBindInfos-parameter', 
-    'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter'                                   : 'VUID-vkCmdDispatchBase-commandBuffer-parameter', 
-    'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter'                                  : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter', 
-    'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter'                           : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter', 
-    'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter'        : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter', 
-    'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter'                             : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter', 
-    'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter'                   : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter', 
-    'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter', 
+khr_aliases = {
+    'VUID-vkBindBufferMemory2KHR-device-parameter'                                        : 'VUID-vkBindBufferMemory2-device-parameter',
+    'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter'                                    : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
+    'VUID-vkBindImageMemory2KHR-device-parameter'                                         : 'VUID-vkBindImageMemory2-device-parameter',
+    'VUID-vkBindImageMemory2KHR-pBindInfos-parameter'                                     : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
+    'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter'                                   : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
+    'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter'                                  : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
+    'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter'                           : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
+    'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter'        : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
+    'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter'                             : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
+    'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter'                   : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
+    'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
     'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent'           : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
-    'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter'                          : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter', 
-    'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter'                            : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter', 
-    'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter'                   : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter', 
+    'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter'                          : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
+    'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter'                            : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
+    'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter'                   : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
     'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent'                      : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
-    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter'                          : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter', 
-    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter'    : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter', 
-    'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter'                             : 'VUID-vkGetBufferMemoryRequirements2-device-parameter', 
-    'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter'                            : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter', 
-    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter'                         : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter', 
-    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter'            : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter', 
-    'VUID-vkGetImageMemoryRequirements2KHR-device-parameter'                              : 'VUID-vkGetImageMemoryRequirements2-device-parameter', 
-    'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter'                        : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter', 
-    'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter'     : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter', 
-    'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter'        : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter'         : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter'     : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter'                       : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter'                       : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter', 
-    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter'          : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter'                     : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter', 
-    'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter'  : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter', 
-    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter'       : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter', 
-    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter'    : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter', 
-    'VUID-vkTrimCommandPoolKHR-commandPool-parameter'                                     : 'VUID-vkTrimCommandPool-commandPool-parameter', 
+    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter'                          : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
+    'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter'    : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
+    'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter'                             : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
+    'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter'                            : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
+    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter'                         : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
+    'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter'            : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
+    'VUID-vkGetImageMemoryRequirements2KHR-device-parameter'                              : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
+    'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter'                        : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
+    'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter'     : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
+    'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter'        : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter'         : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter'     : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter'                       : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter'                       : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
+    'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter'          : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter'               : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter'                     : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
+    'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter'  : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
+    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter'       : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
+    'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter'    : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
+    'VUID-vkTrimCommandPoolKHR-commandPool-parameter'                                     : 'VUID-vkTrimCommandPool-commandPool-parameter',
     'VUID-vkTrimCommandPoolKHR-commandPool-parent'                                        : 'VUID-vkTrimCommandPool-commandPool-parent',
-    'VUID-vkTrimCommandPoolKHR-device-parameter'                                          : 'VUID-vkTrimCommandPool-device-parameter', 
+    'VUID-vkTrimCommandPoolKHR-device-parameter'                                          : 'VUID-vkTrimCommandPool-device-parameter',
     'VUID-vkTrimCommandPoolKHR-flags-zerobitmask'                                         : 'VUID-vkTrimCommandPool-flags-zerobitmask',
-    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter'                   : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter', 
-    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter', 
+    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter'                   : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
+    'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter'        : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
     'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent'           : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
     'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter'                          : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
     'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter'                                : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
@@ -146,8 +150,8 @@
     print ("                                [ -export_header ]")
     print ("                                [ -verbose ]")
     print ("                                [ -help ]")
-    print ("\n  The vk_validation_stats script parses validation layer source files to") 
-    print ("  determine the set of valid usage checks and tests currently implemented,") 
+    print ("\n  The vk_validation_stats script parses validation layer source files to")
+    print ("  determine the set of valid usage checks and tests currently implemented,")
     print ("  and generates coverage values by comparing against the full set of valid")
     print ("  usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
     print ("\nArguments: ")
@@ -173,12 +177,17 @@
         self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
         self.apiversion = ""
         self.duplicate_vuids = set()
-        
+
         # A set of specific regular expression substitutions needed to clean up VUID text
         self.regex_dict = {}
         self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
         self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
+        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
+        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
+        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
+        self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferWidth}{minFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width"
         self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
+        self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
         # Some fancy punctuation chars that break the Android build...
         self.regex_dict[re.compile('&#8594;')] = "->"       # Arrow char
         self.regex_dict[re.compile('&#8217;')] = "'"        # Left-slanting apostrophe to apostrophe
@@ -209,7 +218,7 @@
                 vlist = apidict[ext]
                 for ventry in vlist:
                     vuid_string = ventry['vuid']
-                    if (vuid_string[-5:-1].isdecimal()):    
+                    if (vuid_string[-5:-1].isdecimal()):
                         self.explicit_vuids.add(vuid_string)    # explicit end in 5 numeric chars
                         vtype = 'explicit'
                     else:
@@ -264,7 +273,7 @@
                     if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
                         continue
                     # Find vuid strings
-                    if prepend != None:
+                    if prepend is not None:
                         line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
                         prepend = None
                     if any(prefix in line for prefix in vuid_prefixes):
@@ -275,7 +284,7 @@
                         if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
                             prepend = line
                             continue
-                     
+
                         vuid_list = []
                         for str in line_list:
                             if any(prefix in str for prefix in vuid_prefixes):
@@ -293,7 +302,7 @@
         # Sort vuids by type
         for vuid in self.vuid_count_dict.keys():
             if (vuid.startswith('VUID-')):
-                if (vuid[-5:-1].isdecimal()):    
+                if (vuid[-5:-1].isdecimal()):
                     self.explicit_vuids.add(vuid)    # explicit end in 5 numeric chars
                 else:
                     self.implicit_vuids.add(vuid)
@@ -332,7 +341,7 @@
                         continue
 
                     # if line ends in a broken VUID string, fix that before proceeding
-                    if prepend != None:
+                    if prepend is not None:
                         line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
                         prepend = None
                     if any(prefix in line for prefix in vuid_prefixes):
@@ -343,7 +352,7 @@
                         if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
                             prepend = line
                             continue
-                     
+
                     if any(ttt in line for ttt in self.test_trigger_txt_list):
                         testname = line.split(',')[-1]
                         testname = testname.strip().strip(' {)')
@@ -363,7 +372,7 @@
                                 self.vuid_to_tests[vuid_str].add(testname)
                                 #self.test_to_vuids[testname].append(vuid_str)
                                 if (vuid_str.startswith('VUID-')):
-                                    if (vuid_str[-5:-1].isdecimal()):    
+                                    if (vuid_str[-5:-1].isdecimal()):
                                         self.explicit_vuids.add(vuid_str)    # explicit end in 5 numeric chars
                                     else:
                                         self.implicit_vuids.add(vuid_str)
@@ -440,7 +449,7 @@
         if ignore_unassigned:
             unassigned = set()
             for vuid in undef_set:
-                if vuid.startswith('UNASSIGNED-'): 
+                if vuid.startswith('UNASSIGNED-'):
                     unassigned.add(vuid)
             undef_set = undef_set - unassigned
         if (len(undef_set) > 0):
@@ -464,13 +473,15 @@
         self.vj = val_json
         self.vs = val_source
         self.vt = val_tests
-        self.header_preamble = """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
-/* (scripts/vk_validation_stats.py) */
+        self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
+        self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
+        self.header_version += "\n/* Header generated: %s */\n" % time.strftime('%Y-%m-%d %H:%M:%S')
+        self.header_preamble = """
 /*
  * Vulkan
  *
- * Copyright (c) 2016-2018 Google Inc.
- * Copyright (c) 2016-2018 LunarG, Inc.
+ * Copyright (c) 2016-2019 Google Inc.
+ * Copyright (c) 2016-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -492,7 +503,7 @@
 
 // Disable auto-formatting for generated file
 // clang-format off
-            
+
 // Mapping from VUID string to the corresponding spec text
 typedef struct _vuid_spec_text_pair {
     const char * vuid;
@@ -504,12 +515,12 @@
         self.header_postamble = """};
 """
         self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
-    
+
     def dump_txt(self):
         print("\n Dumping database to text file: %s" % txt_filename)
         with open (txt_filename, 'w') as txt:
             txt.write("## VUID Database\n")
-            txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n") 
+            txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
             vuid_list = list(self.vj.all_vuids)
             vuid_list.sort()
             for vuid in vuid_list:
@@ -532,7 +543,7 @@
         print("\n Dumping database to csv file: %s" % csv_filename)
         with open (csv_filename, 'w', newline='') as csvfile:
             cw = csv.writer(csvfile)
-            cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT']) 
+            cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
             vuid_list = list(self.vj.all_vuids)
             vuid_list.sort()
             for vuid in vuid_list:
@@ -556,7 +567,7 @@
     def dump_html(self):
         print("\n Dumping database to html file: %s" % html_filename)
         preamble = '<!DOCTYPE html>\n<html>\n<head>\n<style>\ntable, th, td {\n border: 1px solid black;\n border-collapse: collapse; \n}\n</style>\n<body>\n<h2>Valid Usage Database</h2>\n<font size="2" face="Arial">\n<table style="width:100%">\n'
-        headers = '<tr><th>VUID NAME</th><th>CHECKED</th><th>TEST</th><th>TYPE</th><th>API/STRUCT</th><th>EXTENSION</th><th>VUID TEXT</th></tr>\n' 
+        headers = '<tr><th>VUID NAME</th><th>CHECKED</th><th>TEST</th><th>TYPE</th><th>API/STRUCT</th><th>EXTENSION</th><th>VUID TEXT</th></tr>\n'
         with open (html_filename, 'w') as hfile:
             hfile.write(preamble)
             hfile.write(headers)
@@ -583,6 +594,7 @@
     def export_header(self):
         print("\n Exporting header file to: %s" % header_filename)
         with open (header_filename, 'w') as hfile:
+            hfile.write(self.header_version)
             hfile.write(self.header_preamble)
             vuid_list = list(self.vj.all_vuids)
             vuid_list.sort()
@@ -608,13 +620,13 @@
     csv_out = False
     html_out = False
     header_out = False
-    
+
     if (1 > len(argv)):
         printHelp()
         sys.exit()
 
     # Parse script args
-    json_filename = argv[0]    
+    json_filename = argv[0]
     i = 1
     while (i < len(argv)):
         arg = argv[i]
@@ -705,7 +717,7 @@
     print("  VUIDs defined in JSON file:  %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
     print("  VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
     print("  VUIDs tested in layer tests: %04d explicit, %04d implicit, %04d total." % (exp_tests, imp_tests, all_tests))
-     
+
     print("\nVUID check coverage")
     print("  Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
     print("  Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
@@ -749,7 +761,7 @@
         ulist = list(unim_explicit)
         ulist.sort()
         for vuid in ulist:
-            print("  => %s" % vuid) 
+            print("  => %s" % vuid)
 
     # Consistency tests
     if run_consistency:
@@ -757,7 +769,7 @@
         con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
         ok = con.undef_vuids_in_layer_code()
         ok &= con.undef_vuids_in_tests()
-        ok &= con.vuids_tested_not_checked() 
+        ok &= con.vuids_tested_not_checked()
 
         if ok:
             print("  OK! No inconsistencies found.")
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f13d2b5..8842edc 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,6 +1,6 @@
 # ~~~
-# Copyright (c) 2014-2018 Valve Corporation
-# Copyright (c) 2014-2018 LunarG, Inc.
+# Copyright (c) 2014-2019 Valve Corporation
+# Copyright (c) 2014-2019 LunarG, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -67,20 +67,21 @@
 if(NOT WIN32)
     # extra setup for out-of-tree builds
     if(NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
-        add_custom_target(binary-dir-symlinks ALL COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/run_all_tests.sh VERBATIM)
+        add_custom_target(VulkanVL_binary_dir_symlinks ALL COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/run_all_tests.sh VERBATIM)
     endif()
 else()
     if(NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
         file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/_run_all_tests.ps1 RUN_ALL)
-        add_custom_target(binary-dir-symlinks ALL
+        add_custom_target(VulkanVL_binary_dir_symlinks ALL
                           COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RUN_ALL} run_all_tests.ps1
                           VERBATIM)
-        set_target_properties(binary-dir-symlinks PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
+        set_target_properties(VulkanVL_binary_dir_symlinks PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
     endif()
 endif()
 
 # ~~~
 # The vulkan loader search is:
+#     Existing vulkan target already present in the build
 #     User-supplied setting of CMAKE_PREFIX_PATH
 #     VULKAN_LOADER_INSTALL_DIR defined via cmake option
 #     VULKAN_LOADER_INSTALL_DIR defined via environment variable
@@ -88,16 +89,18 @@
 # ~~~
 set(VULKAN_LOADER_INSTALL_DIR "LOADER-NOTFOUND" CACHE PATH "Absolute path to a Vulkan-Loader install directory")
 
-if(VULKAN_LOADER_INSTALL_DIR)
-    message(STATUS "VULKAN_LOADER_INSTALL_DIR specified, using find_package to locate Vulkan")
-elseif(ENV{VULKAN_LOADER_INSTALL_DIR})
-    message(STATUS "VULKAN_LOADER_INSTALL_DIR environment variable specified, using find_package to locate Vulkan")
+if(NOT TARGET vulkan)
+    if(VULKAN_LOADER_INSTALL_DIR)
+        message(STATUS "VULKAN_LOADER_INSTALL_DIR specified, using find_package to locate Vulkan")
+    elseif(ENV{VULKAN_LOADER_INSTALL_DIR})
+        message(STATUS "VULKAN_LOADER_INSTALL_DIR environment variable specified, using find_package to locate Vulkan")
+    endif()
+    set(
+        CMAKE_PREFIX_PATH
+        ${CMAKE_PREFIX_PATH};${VULKAN_LOADER_INSTALL_DIR};${VULKAN_HEADERS_INSTALL_DIR};$ENV{VULKAN_LOADER_INSTALL_DIR};$ENV{VULKAN_HEADERS_INSTALL_DIR}
+        )
+    find_package(Vulkan)
 endif()
-set(
-    CMAKE_PREFIX_PATH
-    ${CMAKE_PREFIX_PATH};${VULKAN_LOADER_INSTALL_DIR};${VULKAN_HEADERS_INSTALL_DIR};$ENV{VULKAN_LOADER_INSTALL_DIR};$ENV{VULKAN_HEADERS_INSTALL_DIR}
-    )
-find_package(Vulkan)
 
 set_source_files_properties(${PROJECT_BINARY_DIR}/vk_safe_struct.cpp PROPERTIES GENERATED TRUE)
 add_executable(vk_layer_validation_tests
@@ -106,13 +109,16 @@
                ../layers/convert_to_renderpass2.cpp
                ${PROJECT_BINARY_DIR}/vk_safe_struct.cpp
                ${COMMON_CPP})
-set_target_properties(vk_layer_validation_tests PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+add_dependencies(vk_layer_validation_tests Vulkan::Vulkan)
+if(NOT GTEST_IS_STATIC_LIB)
+    set_target_properties(vk_layer_validation_tests PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+endif()
 target_include_directories(vk_layer_validation_tests
-                           PUBLIC ${VulkanHeaders_INCLUDE_DIR}
-                                  ${CMAKE_CURRENT_SOURCE_DIR}
+                           PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
                                   ${GTEST_LOCATION}/googletest/include
                                   ${PROJECT_SOURCE_DIR}/layers
                                   ${GLSLANG_SPIRV_INCLUDE_DIR}
+                                  ${SPIRV_TOOLS_INCLUDE_DIR}
                                   ${CMAKE_CURRENT_BINARY_DIR}
                                   ${CMAKE_BINARY_DIR}
                                   ${PROJECT_BINARY_DIR}
@@ -121,10 +127,10 @@
                  VkLayer_utils
                  VkLayer_core_validation-json
                  VkLayer_device_profile_api-json
-                 VkLayer_object_tracker-json
-                 VkLayer_parameter_validation-json
+                 VkLayer_object_lifetimes-json
+                 VkLayer_stateless_validation-json
                  VkLayer_standard_validation-json
-                 VkLayer_threading-json
+                 VkLayer_thread_safety-json
                  VkLayer_unique_objects-json)
 
 # Specify target_link_libraries
@@ -155,10 +161,12 @@
 
 if(WIN32)
     # For Windows, copy necessary gtest DLLs to the right spot for the vk_layer_tests...
-    file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googletest/$<CONFIG>/*.dll SRC_GTEST_DLLS)
-    file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG> DST_GTEST_DLLS)
-    add_custom_command(TARGET vk_layer_validation_tests POST_BUILD
-                       COMMAND xcopy /Y /I ${SRC_GTEST_DLLS} ${DST_GTEST_DLLS})
+    if(NOT GTEST_IS_STATIC_LIB)
+        file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/external/googletest/googletest/$<CONFIG>/*.dll SRC_GTEST_DLLS)
+        file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG> DST_GTEST_DLLS)
+        add_custom_command(TARGET vk_layer_validation_tests POST_BUILD
+                           COMMAND xcopy /Y /I ${SRC_GTEST_DLLS} ${DST_GTEST_DLLS})
+    endif()
     # Copy the loader shared lib (if supplied) to the test application directory so the test app finds it.
     if(VULKAN_LOADER_INSTALL_DIR)
         add_custom_command(TARGET vk_layer_validation_tests POST_BUILD
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index b150118..19f221c 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2015-2018 The Khronos Group Inc.
- * Copyright (c) 2015-2018 Valve Corporation
- * Copyright (c) 2015-2018 LunarG, Inc.
- * Copyright (c) 2015-2018 Google, Inc.
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (c) 2015-2019 Google, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -211,6 +211,17 @@
     return sampler_create_info;
 }
 
+// Helper for checking createRenderPass2 support and adding related extensions.
+static bool CheckCreateRenderPass2Support(VkRenderFramework *renderFramework, std::vector<const char *> &device_extension_names) {
+    if (renderFramework->DeviceExtensionSupported(renderFramework->gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
+        device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
+        device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
+        device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
+        return true;
+    }
+    return false;
+}
+
 // Dependent "false" type for the static assert, as GCC will evaluate
 // non-dependent static_asserts even for non-instantiated templates
 template <typename T>
@@ -344,6 +355,11 @@
 
     bool AllDesiredMsgsFound() const { return desired_message_strings_.empty(); }
 
+    void SetError(const char *const errorString) {
+        message_found_ = true;
+        failure_message_strings_.insert(errorString);
+    }
+
     void SetBailout(bool *bailout) { bailout_ = bailout; }
 
     void DumpFailureMsgs() const {
@@ -427,8 +443,8 @@
                                 BsoFailSelect failCase);
 
     void Init(VkPhysicalDeviceFeatures *features = nullptr, VkPhysicalDeviceFeatures2 *features2 = nullptr,
-              const VkCommandPoolCreateFlags flags = 0) {
-        InitFramework(myDbgFunc, m_errorMonitor);
+              const VkCommandPoolCreateFlags flags = 0, void *instance_pnext = nullptr) {
+        InitFramework(myDbgFunc, m_errorMonitor, instance_pnext);
         InitState(features, features2, flags);
     }
 
@@ -694,7 +710,7 @@
     if (failCase == BsoFailCmdClearAttachments) {
         VkClearAttachment color_attachment = {};
         color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-        color_attachment.colorAttachment = 1;  // Someone who knew what they were doing would use 0 for the index;
+        color_attachment.colorAttachment = 2000000000;  // Someone who knew what they were doing would use 0 for the index;
         VkClearRect clear_rect = {{{0, 0}, {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height)}}, 0, 0};
 
         vkCmdClearAttachments(m_commandBuffer->handle(), 1, &color_attachment, 1, &clear_rect);
@@ -1284,6 +1300,20 @@
 };
 }  // namespace chain_util
 
+// PushDescriptorProperties helper
+VkPhysicalDevicePushDescriptorPropertiesKHR GetPushDescriptorProperties(VkInstance instance, VkPhysicalDevice gpu) {
+    // Find address of extension call and make the call -- assumes needed extensions are enabled.
+    PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
+        (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR");
+    assert(vkGetPhysicalDeviceProperties2KHR != nullptr);
+
+    // Get the push descriptor limits
+    auto push_descriptor_prop = lvl_init_struct<VkPhysicalDevicePushDescriptorPropertiesKHR>();
+    auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&push_descriptor_prop);
+    vkGetPhysicalDeviceProperties2KHR(gpu, &prop2);
+    return push_descriptor_prop;
+}
+
 // ********************************************************************************************************************
 // ********************************************************************************************************************
 // ********************************************************************************************************************
@@ -1379,6 +1409,16 @@
     submitInfo.pWaitDstStageMask = &stageFlags;
     vkQueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE);
     m_errorMonitor->VerifyFound();
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSubmitInfo-pWaitSemaphores-parameter");
+    stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.waitSemaphoreCount = 1;
+    // Set a null pointer for pWaitSemaphores
+    submitInfo.pWaitSemaphores = NULL;
+    submitInfo.pWaitDstStageMask = &stageFlags;
+    vkQueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE);
+    m_errorMonitor->VerifyFound();
 }
 
 TEST_F(VkLayerTest, PnextOnlyStructValidation) {
@@ -1502,6 +1542,150 @@
     vkDestroyEvent(m_device->device(), event_handle, NULL);
     m_errorMonitor->VerifyFound();
     vkQueueWaitIdle(m_device->m_queue);
+
+    VkBuffer buffer;
+    VkDeviceMemory memory_1, memory_2;
+    std::string memory_name = "memory_name";
+
+    VkBufferCreateInfo buffer_create_info = {};
+    buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+    buffer_create_info.size = 1;
+
+    vkCreateBuffer(device(), &buffer_create_info, nullptr, &buffer);
+
+    VkMemoryRequirements memRequirements;
+    vkGetBufferMemoryRequirements(device(), buffer, &memRequirements);
+
+    VkMemoryAllocateInfo memory_allocate_info = {};
+    memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    memory_allocate_info.allocationSize = memRequirements.size;
+    memory_allocate_info.memoryTypeIndex = 0;
+
+    vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_1);
+    vkAllocateMemory(device(), &memory_allocate_info, nullptr, &memory_2);
+
+    name_info.object = (uint64_t)memory_2;
+    name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
+    name_info.pObjectName = memory_name.c_str();
+    fpvkDebugMarkerSetObjectNameEXT(device(), &name_info);
+
+    vkBindBufferMemory(device(), buffer, memory_1, 0);
+
+    // Test core_validation layer
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, memory_name);
+    vkBindBufferMemory(device(), buffer, memory_2, 0);
+    m_errorMonitor->VerifyFound();
+
+    vkFreeMemory(device(), memory_1, nullptr);
+    memory_1 = VK_NULL_HANDLE;
+    vkFreeMemory(device(), memory_2, nullptr);
+    memory_2 = VK_NULL_HANDLE;
+    vkDestroyBuffer(device(), buffer, nullptr);
+    buffer = VK_NULL_HANDLE;
+
+    VkCommandBuffer commandBuffer;
+    std::string commandBuffer_name = "command_buffer_name";
+    VkCommandPool commandpool_1;
+    VkCommandPool commandpool_2;
+    VkCommandPoolCreateInfo pool_create_info{};
+    pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
+    pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_1);
+    vkCreateCommandPool(device(), &pool_create_info, nullptr, &commandpool_2);
+
+    VkCommandBufferAllocateInfo command_buffer_allocate_info{};
+    command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    command_buffer_allocate_info.commandPool = commandpool_1;
+    command_buffer_allocate_info.commandBufferCount = 1;
+    command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    vkAllocateCommandBuffers(device(), &command_buffer_allocate_info, &commandBuffer);
+
+    name_info.object = (uint64_t)commandBuffer;
+    name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
+    name_info.pObjectName = commandBuffer_name.c_str();
+    fpvkDebugMarkerSetObjectNameEXT(device(), &name_info);
+
+    VkCommandBufferBeginInfo cb_begin_Info = {};
+    cb_begin_Info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cb_begin_Info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    vkBeginCommandBuffer(commandBuffer, &cb_begin_Info);
+
+    const VkRect2D scissor = {{-1, 0}, {16, 16}};
+    const VkRect2D scissors[] = {scissor, scissor};
+
+    // Test parameter_validation layer
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name);
+    vkCmdSetScissor(commandBuffer, 1, 1, scissors);
+    m_errorMonitor->VerifyFound();
+
+    // Test object_tracker layer
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, commandBuffer_name);
+    vkFreeCommandBuffers(device(), commandpool_2, 1, &commandBuffer);
+    m_errorMonitor->VerifyFound();
+
+    vkDestroyCommandPool(device(), commandpool_1, NULL);
+    vkDestroyCommandPool(device(), commandpool_2, NULL);
+}
+
+TEST_F(VkLayerTest, DebugUtilsNameTest) {
+    // Check for external semaphore instance extensions
+    if (InstanceExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+    } else {
+        printf("%s Debug Utils Extension not supported, skipping test\n", kSkipPrefix);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    ASSERT_NO_FATAL_FAILURE(InitState());
+
+    PFN_vkSetDebugUtilsObjectNameEXT fpvkSetDebugUtilsObjectNameEXT =
+        (PFN_vkSetDebugUtilsObjectNameEXT)vkGetDeviceProcAddr(m_device->device(), "vkSetDebugUtilsObjectNameEXT");
+    if (!(fpvkSetDebugUtilsObjectNameEXT)) {
+        printf("%s Can't find fpvkSetDebugUtilsObjectNameEXT; skipped.\n", kSkipPrefix);
+        return;
+    }
+
+    VkEvent event_handle = VK_NULL_HANDLE;
+    VkEventCreateInfo event_info = {};
+    event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+    vkCreateEvent(device(), &event_info, NULL, &event_handle);
+    VkDebugUtilsObjectNameInfoEXT name_info = {};
+    name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    name_info.pNext = nullptr;
+    name_info.objectHandle = (uint64_t)event_handle;
+    name_info.objectType = VK_OBJECT_TYPE_EVENT;
+    name_info.pObjectName = "Popbutton_T_Bumfuzzle";
+    fpvkSetDebugUtilsObjectNameEXT(device(), &name_info);
+
+    m_commandBuffer->begin();
+    vkCmdSetEvent(m_commandBuffer->handle(), event_handle, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+    m_commandBuffer->end();
+    VkSubmitInfo submit_info = {};
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &m_commandBuffer->handle();
+    vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+    // Provoke an error from the core_validation layer
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Popbutton_T_Bumfuzzle");
+    vkDestroyEvent(m_device->device(), event_handle, NULL);
+    m_errorMonitor->VerifyFound();
+    vkQueueWaitIdle(m_device->m_queue);
+
+    // Provoke an error from the object tracker layer
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Popbutton_T_Bumfuzzle");
+    vkDestroyEvent(m_device->device(), event_handle, NULL);
+    m_errorMonitor->VerifyFound();
+
+    // Change label for a given object, then provoke an error from core_validation and look for the new name
+    name_info.pObjectName = "A_Totally_Different_Name";
+    fpvkSetDebugUtilsObjectNameEXT(device(), &name_info);
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "A_Totally_Different_Name");
+    vkDestroyEvent(m_device->device(), event_handle, NULL);
+    m_errorMonitor->VerifyFound();
+
+    vkQueueWaitIdle(m_device->m_queue);
 }
 
 TEST_F(VkLayerTest, InvalidStructSType) {
@@ -1591,16 +1775,23 @@
 
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "contains flag bits that are not recognized members of");
     // Specify an invalid VkFlags array entry
-    // Expected to trigger an error with
-    // parameter_validation::validate_flags_array
-    VkSemaphore semaphore = VK_NULL_HANDLE;
-    VkPipelineStageFlags stage_flags = static_cast<VkPipelineStageFlags>(1 << 25);
+    // Expected to trigger an error with parameter_validation::validate_flags_array
+    VkSemaphore semaphore;
+    VkSemaphoreCreateInfo semaphore_create_info{};
+    semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore);
+    // `stage_flags` is set to a value which, currently, is not a defined stage flag
+    // `VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM` works well for this
+    VkPipelineStageFlags stage_flags = VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM;
+    // `waitSemaphoreCount` *must* be greater than 0 to perform this check
     VkSubmitInfo submit_info = {};
     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
     submit_info.waitSemaphoreCount = 1;
     submit_info.pWaitSemaphores = &semaphore;
     submit_info.pWaitDstStageMask = &stage_flags;
     vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+    vkDestroySemaphore(m_device->device(), semaphore, nullptr);
+
     m_errorMonitor->VerifyFound();
 }
 
@@ -1719,6 +1910,9 @@
 
     // Both anisotropy and unnormalized coords enabled
     sampler_info.unnormalizedCoordinates = VK_TRUE;
+    // If unnormalizedCoordinates is VK_TRUE, minLod and maxLod must be zero
+    sampler_info.minLod = 0;
+    sampler_info.maxLod = 0;
     do_test("VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01076", &sampler_info);
     sampler_info.unnormalizedCoordinates = sampler_info_ref.unnormalizedCoordinates;
 
@@ -2182,6 +2376,189 @@
     }
 }
 
+TEST_F(VkLayerTest, GpuValidationArrayOOB) {
+    TEST_DESCRIPTION("GPU validation: Verify detection of out-of-bounds descriptor array indexing.");
+    if (!VkRenderFramework::DeviceCanDraw()) {
+        printf("%s GPU-Assisted validation test requires a driver that can draw.\n", kSkipPrefix);
+        return;
+    }
+#if defined(ANDROID)
+    if (instance() == VK_NULL_HANDLE) {
+        printf("%s Skipping test on Android temporarily while debugging test execution failure.\n", kSkipPrefix);
+        return;
+    }
+#endif
+    VkValidationFeatureEnableEXT enables[] = {VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT};
+    VkValidationFeaturesEXT features = {};
+    features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+    features.enabledValidationFeatureCount = 1;
+    features.pEnabledValidationFeatures = enables;
+    VkCommandPoolCreateFlags pool_flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    ASSERT_NO_FATAL_FAILURE(Init(nullptr, nullptr, pool_flags, &features));
+    if (m_device->props.apiVersion < VK_API_VERSION_1_1) {
+        printf("%s GPU-Assisted validation test requires Vulkan 1.1+.\n", kSkipPrefix);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(InitViewport());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    // Make a uniform buffer to be passed to the shader that contains the invalid array index.
+    uint32_t qfi = 0;
+    VkBufferCreateInfo bci = {};
+    bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    bci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+    bci.size = 1024;
+    bci.queueFamilyIndexCount = 1;
+    bci.pQueueFamilyIndices = &qfi;
+    VkBufferObj buffer0;
+    VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+    buffer0.init(*m_device, bci, mem_props);
+    uint32_t *data = (uint32_t *)buffer0.memory().map();
+    data[0] = 25;
+    buffer0.memory().unmap();
+
+    // Prepare descriptors
+    OneOffDescriptorSet ds(m_device, {
+                                         {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
+                                         {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6, VK_SHADER_STAGE_ALL, nullptr},
+                                     });
+
+    const VkPipelineLayoutObj pipeline_layout(m_device, {&ds.layout_});
+    VkTextureObj texture(m_device, nullptr);
+    VkSamplerObj sampler(m_device);
+
+    VkDescriptorBufferInfo buffer_info[1] = {};
+    buffer_info[0].buffer = buffer0.handle();
+    buffer_info[0].offset = 0;
+    buffer_info[0].range = sizeof(uint32_t);
+
+    VkDescriptorImageInfo image_info[6] = {};
+    for (int i = 0; i < 6; i++) {
+        image_info[i] = texture.DescriptorImageInfo();
+        image_info[i].sampler = sampler.handle();
+        image_info[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    }
+
+    VkWriteDescriptorSet descriptor_writes[2] = {};
+    descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_writes[0].dstSet = ds.set_;  // descriptor_set;
+    descriptor_writes[0].dstBinding = 0;
+    descriptor_writes[0].descriptorCount = 1;
+    descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    descriptor_writes[0].pBufferInfo = buffer_info;
+    descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_writes[1].dstSet = ds.set_;  // descriptor_set;
+    descriptor_writes[1].dstBinding = 1;
+    descriptor_writes[1].descriptorCount = 6;
+    descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_writes[1].pImageInfo = image_info;
+    vkUpdateDescriptorSets(m_device->device(), 2, descriptor_writes, 0, NULL);
+
+    // Shader programs for array OOB test in vertex stage:
+    // - The vertex shader fetches the invalid index from the uniform buffer and uses it to make an invalid index into another
+    // array.
+    char const *vsSource_vert =
+        "#version 450\n"
+        "\n"
+        "layout(std140, set = 0, binding = 0) uniform foo { uint tex_index[1]; } uniform_index_buffer;\n"
+        "layout(set = 0, binding = 1) uniform sampler2D tex[6];\n"
+        "vec2 vertices[3];\n"
+        "void main(){\n"
+        "      vertices[0] = vec2(-1.0, -1.0);\n"
+        "      vertices[1] = vec2( 1.0, -1.0);\n"
+        "      vertices[2] = vec2( 0.0,  1.0);\n"
+        "   gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
+        "   gl_Position += 1e-30 * texture(tex[uniform_index_buffer.tex_index[0]], vec2(0, 0));\n"
+        "}\n";
+    char const *fsSource_vert =
+        "#version 450\n"
+        "\n"
+        "layout(set = 0, binding = 1) uniform sampler2D tex[6];\n"
+        "layout(location = 0) out vec4 uFragColor;\n"
+        "void main(){\n"
+        "   uFragColor = texture(tex[0], vec2(0, 0));\n"
+        "}\n";
+
+    // Shader programs for array OOB test in fragment stage:
+    // - The vertex shader fetches the invalid index from the uniform buffer and passes it to the fragment shader.
+    // - The fragment shader makes the invalid array access.
+    char const *vsSource_frag =
+        "#version 450\n"
+        "\n"
+        "layout(std140, binding = 0) uniform foo { uint tex_index[1]; } uniform_index_buffer;\n"
+        "layout(location = 0) out flat uint tex_ind;\n"
+        "vec2 vertices[3];\n"
+        "void main(){\n"
+        "      vertices[0] = vec2(-1.0, -1.0);\n"
+        "      vertices[1] = vec2( 1.0, -1.0);\n"
+        "      vertices[2] = vec2( 0.0,  1.0);\n"
+        "   gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
+        "   tex_ind = uniform_index_buffer.tex_index[0];\n"
+        "}\n";
+    char const *fsSource_frag =
+        "#version 450\n"
+        "\n"
+        "layout(set = 0, binding = 1) uniform sampler2D tex[6];\n"
+        "layout(location = 0) out vec4 uFragColor;\n"
+        "layout(location = 0) in flat uint tex_ind;\n"
+        "void main(){\n"
+        "   uFragColor = texture(tex[tex_ind], vec2(0, 0));\n"
+        "}\n";
+
+    struct TestCase {
+        char const *vertex_source;
+        char const *fragment_source;
+        bool debug;
+        char const *expected_error;
+    };
+
+    std::vector<TestCase> tests;
+    tests.push_back({vsSource_vert, fsSource_vert, false, "Index of 25 used to index descriptor array of length 6."});
+    tests.push_back({vsSource_frag, fsSource_frag, false, "Index of 25 used to index descriptor array of length 6."});
+#if !defined(ANDROID)
+    // The Android test framework uses shaderc for online compilations.  Even when configured to compile with debug info,
+    // shaderc seems to drop the OpLine instructions from the shader binary.  This causes the following two tests to fail
+    // on Android platforms.  Skip these tests until the shaderc issue is understood/resolved.
+    tests.push_back({vsSource_vert, fsSource_vert, true,
+                     "gl_Position += 1e-30 * texture(tex[uniform_index_buffer.tex_index[0]], vec2(0, 0));"});
+    tests.push_back({vsSource_frag, fsSource_frag, true, "uFragColor = texture(tex[tex_ind], vec2(0, 0));"});
+#endif
+
+    VkViewport viewport = m_viewports[0];
+    VkRect2D scissors = m_scissors[0];
+
+    VkSubmitInfo submit_info = {};
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &m_commandBuffer->handle();
+
+    for (const auto &iter : tests) {
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, iter.expected_error);
+        VkShaderObj vs(m_device, iter.vertex_source, VK_SHADER_STAGE_VERTEX_BIT, this, "main", iter.debug);
+        VkShaderObj fs(m_device, iter.fragment_source, VK_SHADER_STAGE_FRAGMENT_BIT, this, "main", iter.debug);
+        VkPipelineObj pipe(m_device);
+        pipe.AddShader(&vs);
+        pipe.AddShader(&fs);
+        pipe.AddDefaultColorAttachment();
+        VkResult err = pipe.CreateVKPipeline(pipeline_layout.handle(), renderPass());
+        ASSERT_VK_SUCCESS(err);
+        m_commandBuffer->begin();
+        m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
+        vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
+        vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
+                                &ds.set_, 0, nullptr);
+        vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
+        vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissors);
+        vkCmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
+        vkCmdEndRenderPass(m_commandBuffer->handle());
+        m_commandBuffer->end();
+        vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+        vkQueueWaitIdle(m_device->m_queue);
+        m_errorMonitor->VerifyFound();
+    }
+    return;
+}
+
 TEST_F(VkLayerTest, InvalidMemoryAliasing) {
     TEST_DESCRIPTION(
         "Create a buffer and image, allocate memory, and bind the buffer and image to memory such that they will alias.");
@@ -2486,7 +2863,7 @@
     image_create_info.mipLevels = 1;
     image_create_info.arrayLayers = 1;
     image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
-    image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
     image_create_info.flags = 0;
 
@@ -2529,6 +2906,41 @@
     vkFreeMemory(m_device->device(), mem2, NULL);
 }
 
+TEST_F(VkLayerTest, QueryMemoryCommitmentWithoutLazyProperty) {
+    TEST_DESCRIPTION("Attempt to query memory commitment on memory without lazy allocation");
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    auto image_ci = vk_testing::Image::create_info();
+    image_ci.imageType = VK_IMAGE_TYPE_2D;
+    image_ci.format = VK_FORMAT_B8G8R8A8_UNORM;
+    image_ci.extent.width = 32;
+    image_ci.extent.height = 32;
+    image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
+    image_ci.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    vk_testing::Image image;
+    image.init_no_mem(*m_device, image_ci);
+
+    auto mem_reqs = image.memory_requirements();
+    // memory_type_index is set to 0 here, but is set properly below
+    auto image_alloc_info = vk_testing::DeviceMemory::alloc_info(mem_reqs.size, 0);
+
+    bool pass;
+    // the last argument is the "forbid" argument for set_memory_type, disallowing
+    // that particular memory type rather than requiring it
+    pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &image_alloc_info, 0, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT);
+    if (!pass) {
+        printf("%s Failed to set memory type.\n", kSkipPrefix);
+        return;
+    }
+    vk_testing::DeviceMemory mem;
+    mem.init(*m_device, image_alloc_info);
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetDeviceMemoryCommitment-memory-00690");
+    VkDeviceSize size;
+    vkGetDeviceMemoryCommitment(m_device->device(), mem.handle(), &size);
+    m_errorMonitor->VerifyFound();
+}
+
 TEST_F(VkLayerTest, SubmitSignaledFence) {
     vk_testing::Fence testFence;
 
@@ -3259,7 +3671,7 @@
     image_create_info.mipLevels = 1;
     image_create_info.arrayLayers = 1;
     image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
-    image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
     image_create_info.flags = 0;
 
@@ -3828,8 +4240,7 @@
     m_commandBuffer->begin();
 
     // Source image in invalid layout at start of the CB
-    m_errorMonitor->SetDesiredFailureMsg(
-        VK_DEBUG_REPORT_ERROR_BIT_EXT, "layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when first use is VK_IMAGE_LAYOUT_GENERAL");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout");
     vkCmdBlitImage(m_commandBuffer->handle(), img_src_transfer.image(), img_src_transfer.Layout(), img_color.image(),
                    VK_IMAGE_LAYOUT_GENERAL, 1, &blit_region, VK_FILTER_LINEAR);
 
@@ -3843,8 +4254,7 @@
     m_commandBuffer->begin();
 
     // Destination image in invalid layout at start of the CB
-    m_errorMonitor->SetDesiredFailureMsg(
-        VK_DEBUG_REPORT_ERROR_BIT_EXT, "layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when first use is VK_IMAGE_LAYOUT_GENERAL");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout");
     vkCmdBlitImage(m_commandBuffer->handle(), img_color.image(), VK_IMAGE_LAYOUT_GENERAL, img_dst_transfer.image(),
                    img_dst_transfer.Layout(), 1, &blit_region, VK_FILTER_LINEAR);
 
@@ -4719,7 +5129,7 @@
     VkImageObj lone_image(m_device);
     lone_image.InitNoLayout(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
     img_barrier.image = lone_image.handle();
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-01179");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-02635");
     vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1,
                          &img_barrier);
@@ -4735,7 +5145,7 @@
 
     img_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
     img_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-oldLayout-01180");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-oldLayout-02636");
     vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1,
                          &img_barrier);
@@ -4835,7 +5245,7 @@
                          VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &img_barrier);
     secondary.end();
 
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-01179");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-02635");
     vkCmdExecuteCommands(m_commandBuffer->handle(), 1, &secondary.handle());
     m_errorMonitor->VerifyFound();
 
@@ -4847,7 +5257,7 @@
     TEST_DESCRIPTION("Check case where subpass index references different image from image barrier");
     ASSERT_NO_FATAL_FAILURE(Init());
 
-    // Create RP/FB combo where subpass has incorrect index attachment, this is 2nd half of "VUID-vkCmdPipelineBarrier-image-01179"
+    // Create RP/FB combo where subpass has incorrect index attachment, this is 2nd half of "VUID-vkCmdPipelineBarrier-image-02635"
     VkAttachmentDescription attach[] = {
         {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
          VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
@@ -4917,7 +5327,7 @@
     img_barrier.subresourceRange.levelCount = 1;
     m_commandBuffer->begin();
     vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE);
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-01179");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-image-02635");
     vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1,
                          &img_barrier);
@@ -5283,8 +5693,7 @@
 }
 
 static void TestRenderPassCreate(ErrorMonitor *error_monitor, const VkDevice device, const VkRenderPassCreateInfo *create_info,
-                                 PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR, const char *rp1_vuid, const char *rp2_vuid) {
-    // "... must be less than the total number of attachments ..."
+                                 bool rp2Supported, const char *rp1_vuid, const char *rp2_vuid) {
     VkRenderPass render_pass = VK_NULL_HANDLE;
     VkResult err;
 
@@ -5295,7 +5704,9 @@
         error_monitor->VerifyFound();
     }
 
-    if (vkCreateRenderPass2KHR && rp2_vuid) {
+    if (rp2Supported && rp2_vuid) {
+        PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR =
+            (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(device, "vkCreateRenderPass2KHR");
         safe_VkRenderPassCreateInfo2KHR create_info2;
         ConvertVkRenderPassCreateInfoToV2KHR(create_info, &create_info2);
 
@@ -5313,22 +5724,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     // There are no attachments, but refer to attachment 0.
     VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
     VkSubpassDescription subpasses[] = {
@@ -5338,8 +5736,8 @@
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr};
 
     // "... must be less than the total number of attachments ..."
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkRenderPassCreateInfo-attachment-00834", "VUID-VkRenderPassCreateInfo2KHR-attachment-03051");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-attachment-00834",
+                         "VUID-VkRenderPassCreateInfo2KHR-attachment-03051");
 }
 
 TEST_F(VkLayerTest, RenderPassCreateAttachmentReadOnlyButCleared) {
@@ -5349,31 +5747,22 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-    bool maintenance2Supported = false;
+
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
+    bool maintenance2Supported = rp2Supported;
 
     // Check for VK_KHR_maintenance2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) {
+    if (!rp2Supported && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
         maintenance2Supported = true;
     }
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+
     ASSERT_NO_FATAL_FAILURE(InitState());
 
     if (m_device->props.apiVersion < VK_API_VERSION_1_1) {
         maintenance2Supported = true;
     }
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkAttachmentDescription description = {0,
                                            VK_FORMAT_D32_SFLOAT_S8_UINT,
                                            VK_SAMPLE_COUNT_1_BIT,
@@ -5392,26 +5781,26 @@
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &description, 1, &subpass, 0, nullptr};
 
     // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL but depth cleared
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkRenderPassCreateInfo-pAttachments-00836", "VUID-VkRenderPassCreateInfo2KHR-pAttachments-03053");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-pAttachments-00836",
+                         "VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522");
 
     if (maintenance2Supported) {
         // VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL but depth cleared
         depth_stencil_ref.layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                              "VUID-VkRenderPassCreateInfo-pAttachments-01566", nullptr);
 
         // VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL but depth cleared
         depth_stencil_ref.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                              "VUID-VkRenderPassCreateInfo-pAttachments-01567", nullptr);
     }
 }
 
-TEST_F(VkLayerTest, RenderPassCreateAttachmentUsedTwiceColor) {
-    TEST_DESCRIPTION("Attachment is used simultaneously as two color attachments. This is usually unintended.");
+TEST_F(VkLayerTest, RenderPassCreateAttachmentMismatchingLayoutsColor) {
+    TEST_DESCRIPTION("Attachment is used simultaneously as two color attachments with different layouts.");
 
     // Check for VK_KHR_get_physical_device_properties2
     if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
@@ -5419,22 +5808,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkAttachmentDescription attach[] = {
         {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
          VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
@@ -5442,7 +5818,7 @@
     };
     VkAttachmentReference refs[] = {
         {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
-        {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+        {0, VK_IMAGE_LAYOUT_GENERAL},
     };
     VkSubpassDescription subpasses[] = {
         {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 2, refs, nullptr, nullptr, 0, nullptr},
@@ -5450,9 +5826,9 @@
 
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "subpass 0 already uses attachment 0 as a color attachment",
-                         "subpass 0 already uses attachment 0 as a color attachment");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
+                         "subpass 0 already uses attachment 0 with a different image layout",
+                         "subpass 0 already uses attachment 0 with a different image layout");
 }
 
 TEST_F(VkLayerTest, RenderPassCreateAttachmentDescriptionInvalidFinalLayout) {
@@ -5464,22 +5840,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkAttachmentDescription attach_desc = {};
     attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM;
     attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
@@ -5503,12 +5866,12 @@
     rpci.subpassCount = 1;
     rpci.pSubpasses = &subpass;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkAttachmentDescription-finalLayout-00843", "VUID-VkAttachmentDescription2KHR-finalLayout-03061");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkAttachmentDescription-finalLayout-00843",
+                         "VUID-VkAttachmentDescription2KHR-finalLayout-03061");
 
     attach_desc.finalLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkAttachmentDescription-finalLayout-00843", "VUID-VkAttachmentDescription2KHR-finalLayout-03061");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkAttachmentDescription-finalLayout-00843",
+                         "VUID-VkAttachmentDescription2KHR-finalLayout-03061");
 }
 
 TEST_F(VkLayerTest, RenderPassCreateAttachmentsMisc) {
@@ -5522,22 +5885,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     std::vector<VkAttachmentDescription> attachments = {
         // input attachments
         {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
@@ -5605,7 +5955,7 @@
         subpass.pColorAttachments = too_many_colors.data();
         subpass.pResolveAttachments = NULL;
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                              "VUID-VkSubpassDescription-colorAttachmentCount-00845",
                              "VUID-VkSubpassDescription2KHR-colorAttachmentCount-03063");
 
@@ -5618,7 +5968,7 @@
     attachments[subpass.pColorAttachments[1].attachment].samples = VK_SAMPLE_COUNT_8_BIT;
     depth.attachment = VK_ATTACHMENT_UNUSED;  // Avoids triggering 01418
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pColorAttachments-01417",
                          "VUID-VkSubpassDescription2KHR-pColorAttachments-03069");
 
@@ -5629,7 +5979,7 @@
     attachments[subpass.pDepthStencilAttachment->attachment].samples = VK_SAMPLE_COUNT_8_BIT;
     subpass.colorAttachmentCount = 1;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pDepthStencilAttachment-01418",
                          "VUID-VkSubpassDescription2KHR-pDepthStencilAttachment-03071");
 
@@ -5639,7 +5989,7 @@
     // Test resolve attachment with UNUSED color attachment
     color[0].attachment = VK_ATTACHMENT_UNUSED;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pResolveAttachments-00847",
                          "VUID-VkSubpassDescription2KHR-pResolveAttachments-03065");
 
@@ -5650,7 +6000,7 @@
     subpass.colorAttachmentCount = 1;           // avoid mismatch (00337), and avoid double report
     subpass.pDepthStencilAttachment = nullptr;  // avoid mismatch (01418)
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pResolveAttachments-00848",
                          "VUID-VkSubpassDescription2KHR-pResolveAttachments-03066");
 
@@ -5661,7 +6011,7 @@
     // Test resolve to a multi-sampled resolve attachment
     attachments[subpass.pResolveAttachments[0].attachment].samples = VK_SAMPLE_COUNT_4_BIT;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pResolveAttachments-00849",
                          "VUID-VkSubpassDescription2KHR-pResolveAttachments-03067");
 
@@ -5670,7 +6020,7 @@
     // Test with color/resolve format mismatch
     attachments[subpass.pColorAttachments[0].attachment].format = VK_FORMAT_R8G8B8A8_SRGB;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pResolveAttachments-00850",
                          "VUID-VkSubpassDescription2KHR-pResolveAttachments-03068");
 
@@ -5679,36 +6029,18 @@
     // Test for UNUSED preserve attachments
     preserve[0] = VK_ATTACHMENT_UNUSED;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDescription-attachment-00853", "VUID-VkSubpassDescription2KHR-attachment-03073");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDescription-attachment-00853",
+                         "VUID-VkSubpassDescription2KHR-attachment-03073");
 
     preserve[0] = 5;
     // Test for preserve attachments used elsewhere in the subpass
     color[0].attachment = preserve[0];
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pPreserveAttachments-00854",
                          "VUID-VkSubpassDescription2KHR-pPreserveAttachments-03074");
 
     color[0].attachment = 1;
-
-    // Test for layout mismatch between input attachment and color attachment
-    input[0].attachment = color[0].attachment;
-    input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDescription-layout-00855", "VUID-VkSubpassDescription2KHR-layout-03075");
-
-    input[0].attachment = 0;
-    input[0].layout = VK_IMAGE_LAYOUT_GENERAL;
-
-    // Test for layout mismatch between input attachment and depth attachment
-    input[0].attachment = depth.attachment;
-    input[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDescription-layout-00855", "VUID-VkSubpassDescription2KHR-layout-03075");
-
     input[0].attachment = 0;
     input[0].layout = VK_IMAGE_LAYOUT_GENERAL;
 
@@ -5728,7 +6060,7 @@
                                                  0,
                                                  nullptr};
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci_multipass, vkCreateRenderPass2KHR,
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci_multipass, rp2Supported,
                              "VUID-VkSubpassDescription-loadOp-00846", "VUID-VkSubpassDescription2KHR-loadOp-03064");
 
         attachments[input[0].attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@@ -5744,22 +6076,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkAttachmentDescription attach[] = {
         {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
          VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
@@ -5775,13 +6094,13 @@
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attach, 1, subpasses, 0, nullptr};
 
     // Use UNDEFINED layout
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkAttachmentReference-layout-00857", "VUID-VkAttachmentReference2KHR-layout-03077");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkAttachmentReference-layout-00857",
+                         "VUID-VkAttachmentReference2KHR-layout-03077");
 
     // Use PREINITIALIZED layout
     refs[0].layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkAttachmentReference-layout-00857", "VUID-VkAttachmentReference2KHR-layout-03077");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkAttachmentReference-layout-00857",
+                         "VUID-VkAttachmentReference2KHR-layout-03077");
 }
 
 TEST_F(VkLayerTest, RenderPassCreateOverlappingCorrelationMasks) {
@@ -5793,28 +6112,19 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
 
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-    } else {
-        printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        return;
+    if (!rp2Supported) {
+        if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
+            m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
+        } else {
+            printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME);
+            return;
+        }
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
     uint32_t viewMasks[] = {0x3u};
     uint32_t correlationMasks[] = {0x1u, 0x3u};
@@ -5824,12 +6134,15 @@
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpmvci, 0, 0, nullptr, 1, &subpass, 0, nullptr};
 
     // Correlation masks must not overlap
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841",
                          "VUID-VkRenderPassCreateInfo2KHR-pCorrelatedViewMasks-03056");
 
     // Check for more specific "don't set any correlation masks when multiview is not enabled"
     if (rp2Supported) {
+        PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR =
+            (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
+
         viewMasks[0] = 0;
         correlationMasks[0] = 0;
         correlationMasks[1] = 0;
@@ -5853,28 +6166,19 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
 
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-    } else {
-        printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        return;
+    if (!rp2Supported) {
+        if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
+            m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
+        } else {
+            printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_MULTIVIEW_EXTENSION_NAME);
+            return;
+        }
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkSubpassDescription subpasses[] = {
         {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
         {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
@@ -5886,8 +6190,8 @@
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpmvci, 0, 0, nullptr, 2, subpasses, 0, nullptr};
 
     // Not enough view masks
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkRenderPassCreateInfo-pNext-01928", "VUID-VkRenderPassCreateInfo2KHR-viewMask-03058");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-pNext-01928",
+                         "VUID-VkRenderPassCreateInfo2KHR-viewMask-03058");
 }
 
 TEST_F(VkLayerTest, RenderPassCreateInvalidInputAttachmentReferences) {
@@ -5925,22 +6229,22 @@
     // Invalid meta data aspect
     m_errorMonitor->SetDesiredFailureMsg(
         VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkRenderPassCreateInfo-pNext-01963");  // Cannot/should not avoid getting this one too
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr,
-                         "VUID-VkInputAttachmentAspectReference-aspectMask-01964", nullptr);
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkInputAttachmentAspectReference-aspectMask-01964",
+                         nullptr);
 
     // Aspect not present
     iaar.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01963", nullptr);
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkRenderPassCreateInfo-pNext-01963", nullptr);
 
     // Invalid subpass index
     iaar.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     iaar.subpass = 1;
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01926", nullptr);
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkRenderPassCreateInfo-pNext-01926", nullptr);
     iaar.subpass = 0;
 
     // Invalid input attachment index
     iaar.inputAttachmentIndex = 1;
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01927", nullptr);
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkRenderPassCreateInfo-pNext-01927", nullptr);
 }
 
 TEST_F(VkLayerTest, RenderPassCreateSubpassNonGraphicsPipeline) {
@@ -5951,29 +6255,16 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkSubpassDescription subpasses[] = {
         {0, VK_PIPELINE_BIND_POINT_COMPUTE, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
     };
 
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pipelineBindPoint-00844",
                          "VUID-VkSubpassDescription2KHR-pipelineBindPoint-03062");
 }
@@ -5990,10 +6281,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
 
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME)) {
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME) &&
+        DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME);
         m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
     } else {
@@ -6001,18 +6291,9 @@
         return;
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     VkSubpassDescription subpasses[] = {
         {VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr,
          nullptr, 0, nullptr},
@@ -6020,7 +6301,7 @@
 
     VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, subpasses, 0, nullptr};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, "VUID-VkSubpassDescription-flags-00856",
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDescription-flags-00856",
                          "VUID-VkSubpassDescription2KHR-flags-03076");
 }
 
@@ -6037,11 +6318,9 @@
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
 
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-    } else {
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
+
+    if (!rp2Supported) {
         printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
         return;
     }
@@ -6049,7 +6328,7 @@
     ASSERT_NO_FATAL_FAILURE(InitState());
 
     PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR =
-        (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
+        rp2Supported ? (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR") : nullptr;
 
     VkResult err;
 
@@ -6094,22 +6373,15 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-    bool multiviewSupported = false;
 
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
+    bool multiviewSupported = rp2Supported;
+
+    if (!rp2Supported && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
         multiviewSupported = true;
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
-
     // Add a device features struct enabling NO features
     VkPhysicalDeviceFeatures features = {0};
     ASSERT_NO_FATAL_FAILURE(InitState(&features));
@@ -6118,10 +6390,6 @@
         multiviewSupported = true;
     }
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
-
     // Create two dummy subpasses
     VkSubpassDescription subpasses[] = {
         {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
@@ -6135,96 +6403,96 @@
     // Source subpass is not EXTERNAL, so source stage mask must not include HOST
     dependency = {0, 1, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcSubpass-00858", "VUID-VkSubpassDependency2KHR-srcSubpass-03078");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-00858",
+                         "VUID-VkSubpassDependency2KHR-srcSubpass-03078");
 
     // Destination subpass is not EXTERNAL, so destination stage mask must not include HOST
     dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-dstSubpass-00859", "VUID-VkSubpassDependency2KHR-dstSubpass-03079");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-dstSubpass-00859",
+                         "VUID-VkSubpassDependency2KHR-dstSubpass-03079");
 
     // Geometry shaders not enabled source
     dependency = {0, 1, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcStageMask-00860", "VUID-VkSubpassDependency2KHR-srcStageMask-03080");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcStageMask-00860",
+                         "VUID-VkSubpassDependency2KHR-srcStageMask-03080");
 
     // Geometry shaders not enabled destination
     dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-dstStageMask-00861", "VUID-VkSubpassDependency2KHR-dstStageMask-03081");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-dstStageMask-00861",
+                         "VUID-VkSubpassDependency2KHR-dstStageMask-03081");
 
     // Tessellation not enabled source
     dependency = {0, 1, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcStageMask-00862", "VUID-VkSubpassDependency2KHR-srcStageMask-03082");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcStageMask-00862",
+                         "VUID-VkSubpassDependency2KHR-srcStageMask-03082");
 
     // Tessellation not enabled destination
     dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-dstStageMask-00863", "VUID-VkSubpassDependency2KHR-dstStageMask-03083");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-dstStageMask-00863",
+                         "VUID-VkSubpassDependency2KHR-dstStageMask-03083");
 
     // Potential cyclical dependency
     dependency = {1, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcSubpass-00864", "VUID-VkSubpassDependency2KHR-srcSubpass-03084");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-00864",
+                         "VUID-VkSubpassDependency2KHR-srcSubpass-03084");
 
     // EXTERNAL to EXTERNAL dependency
     dependency = {
         VK_SUBPASS_EXTERNAL, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcSubpass-00865", "VUID-VkSubpassDependency2KHR-srcSubpass-03085");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-00865",
+                         "VUID-VkSubpassDependency2KHR-srcSubpass-03085");
 
     // Source compute stage not part of subpass 0's GRAPHICS pipeline
     dependency = {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkRenderPassCreateInfo-pDependencies-00837", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-pDependencies-00837",
+                         "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03054");
 
     // Destination compute stage not part of subpass 0's GRAPHICS pipeline
     dependency = {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkRenderPassCreateInfo-pDependencies-00838", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-pDependencies-00838",
+                         "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03055");
 
     // Non graphics stage in self dependency
     dependency = {0, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcSubpass-01989", "VUID-VkSubpassDependency2KHR-srcSubpass-02244");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-01989",
+                         "VUID-VkSubpassDependency2KHR-srcSubpass-02244");
 
     // Logically later source stages in self dependency
     dependency = {0, 0, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcSubpass-00867", "VUID-VkSubpassDependency2KHR-srcSubpass-03087");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-00867",
+                         "VUID-VkSubpassDependency2KHR-srcSubpass-03087");
 
     // Source access mask mismatch with source stage mask
     dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_ACCESS_UNIFORM_READ_BIT, 0, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-srcAccessMask-00868", "VUID-VkSubpassDependency2KHR-srcAccessMask-03088");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcAccessMask-00868",
+                         "VUID-VkSubpassDependency2KHR-srcAccessMask-03088");
 
     // Destination access mask mismatch with destination stage mask
     dependency = {
         0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0};
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                         "VUID-VkSubpassDependency-dstAccessMask-00869", "VUID-VkSubpassDependency2KHR-dstAccessMask-03089");
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-dstAccessMask-00869",
+                         "VUID-VkSubpassDependency2KHR-dstAccessMask-03089");
 
     if (multiviewSupported) {
         // VIEW_LOCAL_BIT but multiview is not enabled
         dependency = {0, 1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
                       0, 0, VK_DEPENDENCY_VIEW_LOCAL_BIT};
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                             "VUID-VkSubpassDependency-dependencyFlags-00871", "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059");
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, nullptr,
+                             "VUID-VkRenderPassCreateInfo2KHR-viewMask-03059");
 
         // Enable multiview
         uint32_t pViewMasks[2] = {0x3u, 0x3u};
@@ -6239,8 +6507,7 @@
         rpmvci.pViewOffsets = pViewOffsets;
         rpmvci.dependencyCount = 2;
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01929",
-                             nullptr);
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkRenderPassCreateInfo-pNext-01929", nullptr);
 
         rpmvci.dependencyCount = 0;
 
@@ -6251,8 +6518,7 @@
         pViewOffsets[0] = 1;
         rpmvci.dependencyCount = 1;
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, nullptr, "VUID-VkRenderPassCreateInfo-pNext-01930",
-                             nullptr);
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkRenderPassCreateInfo-pNext-01930", nullptr);
 
         rpmvci.dependencyCount = 0;
 
@@ -6266,7 +6532,7 @@
             safe_VkRenderPassCreateInfo2KHR safe_rpci2;
             ConvertVkRenderPassCreateInfoToV2KHR(&rpci, &safe_rpci2);
 
-            TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR, nullptr,
+            TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, nullptr,
                                  "VUID-VkSubpassDependency2KHR-dependencyFlags-03092");
 
             rpmvci.dependencyCount = 0;
@@ -6276,23 +6542,23 @@
         dependency = {VK_SUBPASS_EXTERNAL,         1, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0,
                       VK_DEPENDENCY_VIEW_LOCAL_BIT};
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                             "VUID-VkSubpassDependency-dependencyFlags-00870",
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
+                             "VUID-VkSubpassDependency-dependencyFlags-02520",
                              "VUID-VkSubpassDependency2KHR-dependencyFlags-03090");
 
         // EXTERNAL subpass with VIEW_LOCAL_BIT - destination subpass
         dependency = {0, VK_SUBPASS_EXTERNAL,         VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
                       0, VK_DEPENDENCY_VIEW_LOCAL_BIT};
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                             "VUID-VkSubpassDependency-dependencyFlags-00870",
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
+                             "VUID-VkSubpassDependency-dependencyFlags-02521",
                              "VUID-VkSubpassDependency2KHR-dependencyFlags-03091");
 
         // Multiple views but no view local bit in self-dependency
         dependency = {0, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0};
 
-        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
-                             "VUID-VkSubpassDependency-srcSubpass-00872", "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060");
+        TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported, "VUID-VkSubpassDependency-srcSubpass-00872",
+                             "VUID-VkRenderPassCreateInfo2KHR-pDependencies-03060");
     }
 }
 
@@ -6305,8 +6571,6 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
 
     if (DeviceExtensionSupported(gpu(), nullptr, VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME);
@@ -6315,18 +6579,9 @@
         return;
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
-    ASSERT_NO_FATAL_FAILURE(InitState());
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
 
-    if (rp2Supported) {
-        vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateRenderPass2KHR");
-    }
+    ASSERT_NO_FATAL_FAILURE(InitState());
 
     std::vector<VkAttachmentDescription> attachments;
 
@@ -6389,16 +6644,14 @@
     attachments[0].samples = VK_SAMPLE_COUNT_4_BIT;
     attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
 
-    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, vkCreateRenderPass2KHR,
+    TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, rp2Supported,
                          "VUID-VkSubpassDescription-pColorAttachments-01506",
                          "VUID-VkSubpassDescription2KHR-pColorAttachments-03070");
 }
 
-static void TestRenderPassBegin(ErrorMonitor *error_monitor, const VkCommandBuffer command_buffer,
-                                const VkRenderPassBeginInfo *begin_info, PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR,
-                                const char *rp1_vuid, const char *rp2_vuid) {
-    // "... must be less than the total number of attachments ..."
-
+static void TestRenderPassBegin(ErrorMonitor *error_monitor, const VkDevice device, const VkCommandBuffer command_buffer,
+                                const VkRenderPassBeginInfo *begin_info, bool rp2Supported, const char *rp1_vuid,
+                                const char *rp2_vuid) {
     VkCommandBufferBeginInfo cmd_begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
                                                VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr};
 
@@ -6409,7 +6662,9 @@
         error_monitor->VerifyFound();
         vkResetCommandBuffer(command_buffer, 0);
     }
-    if (vkCmdBeginRenderPass2KHR && rp2_vuid) {
+    if (rp2Supported && rp2_vuid) {
+        PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR =
+            (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(device, "vkCmdBeginRenderPass2KHR");
         VkSubpassBeginInfoKHR subpass_begin_info = {VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR, nullptr, VK_SUBPASS_CONTENTS_INLINE};
         vkBeginCommandBuffer(command_buffer, &cmd_begin_info);
         error_monitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, rp2_vuid);
@@ -6427,30 +6682,16 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
 
-    if (rp2Supported) {
-        vkCmdBeginRenderPass2KHR =
-            (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR");
-    }
-
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
     // Framebuffer for render target is 256x256, exceed that for INVALID_RENDER_AREA
     m_renderPassBeginInfo.renderArea.extent.width = 257;
     m_renderPassBeginInfo.renderArea.extent.height = 257;
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &m_renderPassBeginInfo, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &m_renderPassBeginInfo, rp2Supported,
                         "Cannot execute a render pass with renderArea not within the bound of the framebuffer.",
                         "Cannot execute a render pass with renderArea not within the bound of the framebuffer.");
 }
@@ -6463,15 +6704,7 @@
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
     PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
     if (rp2Supported) {
@@ -6556,7 +6789,7 @@
 
     VkRenderPassBeginInfo rp_begin = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp2, fb, {{0, 0}, {128, 128}}, 0, nullptr};
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, false,
                         "VUID-VkRenderPassBeginInfo-renderPass-00904", nullptr);
 
     vkDestroyRenderPass(m_device->device(), rp1, nullptr);
@@ -6575,33 +6808,21 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-    bool maintenance2Supported = false;
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
+    bool maintenance2Supported = rp2Supported;
 
     // Check for VK_KHR_maintenance2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) {
+    if (!rp2Supported && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE2_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
         maintenance2Supported = true;
     }
 
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
 
     if (m_device->props.apiVersion >= VK_API_VERSION_1_1) {
         maintenance2Supported = true;
     }
 
-    if (rp2Supported) {
-        vkCmdBeginRenderPass2KHR =
-            (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR");
-    }
-
     // Create an input attachment view
     VkImageObj iai(m_device);
 
@@ -6675,7 +6896,7 @@
     descriptions[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
     vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
     rp_begin.renderPass = rp_invalid;
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                         "VUID-vkCmdBeginRenderPass-initialLayout-00895", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6687,7 +6908,7 @@
     vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
     rp_begin.renderPass = rp_invalid;
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                         "VUID-vkCmdBeginRenderPass-initialLayout-00897", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6698,7 +6919,7 @@
     vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
     rp_begin.renderPass = rp_invalid;
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                         "VUID-vkCmdBeginRenderPass-initialLayout-00898", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6708,7 +6929,7 @@
     vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
     rp_begin.renderPass = rp_invalid;
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                         "VUID-vkCmdBeginRenderPass-initialLayout-00899", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6721,8 +6942,8 @@
     const char *initial_layout_vuid_rp1 =
         maintenance2Supported ? "VUID-vkCmdBeginRenderPass-initialLayout-01758" : "VUID-vkCmdBeginRenderPass-initialLayout-00896";
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, initial_layout_vuid_rp1,
-                        "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
+                        initial_layout_vuid_rp1, "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
 
@@ -6732,8 +6953,8 @@
     vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
     rp_begin.renderPass = rp_invalid;
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR, initial_layout_vuid_rp1,
-                        "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
+                        initial_layout_vuid_rp1, "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
 
     vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
 
@@ -6744,7 +6965,7 @@
         vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
         rp_begin.renderPass = rp_invalid;
 
-        TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+        TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                             "VUID-vkCmdBeginRenderPass-initialLayout-01758", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
 
         vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6755,7 +6976,7 @@
         vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp_invalid);
         rp_begin.renderPass = rp_invalid;
 
-        TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+        TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                             "VUID-vkCmdBeginRenderPass-initialLayout-01758", "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096");
 
         vkDestroyRenderPass(m_device->handle(), rp_invalid, nullptr);
@@ -6778,23 +6999,9 @@
     }
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    PFN_vkCmdBeginRenderPass2KHR vkCmdBeginRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
 
-    if (rp2Supported) {
-        vkCmdBeginRenderPass2KHR =
-            (PFN_vkCmdBeginRenderPass2KHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdBeginRenderPass2KHR");
-    }
-
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
     // Create a renderPass with a single attachment that uses loadOp CLEAR
@@ -6825,7 +7032,7 @@
     rp_begin.framebuffer = framebuffer();
     rp_begin.clearValueCount = 0;  // Should be 1
 
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, vkCmdBeginRenderPass2KHR,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, rp2Supported,
                         "VUID-VkRenderPassBeginInfo-clearValueCount-00902", "VUID-VkRenderPassBeginInfo-clearValueCount-00902");
 
     vkDestroyRenderPass(m_device->device(), rp, NULL);
@@ -6834,6 +7041,10 @@
 TEST_F(VkLayerTest, RenderPassBeginSampleLocationsInvalidIndicesEXT) {
     TEST_DESCRIPTION("Test that attachment indices and subpass indices specifed by sample locations structures are valid");
 
+    // Check for VK_KHR_get_physical_device_properties2
+    if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
     if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
@@ -6910,12 +7121,12 @@
         VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, &rp_sl_begin, rp, fb, {{0, 0}, {128, 128}}, 0, nullptr};
 
     attachment_sample_locations.attachmentIndex = 1;
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, false,
                         "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531", nullptr);
     attachment_sample_locations.attachmentIndex = 0;
 
     subpass_sample_locations.subpassIndex = 1;
-    TestRenderPassBegin(m_errorMonitor, m_commandBuffer->handle(), &rp_begin, nullptr,
+    TestRenderPassBegin(m_errorMonitor, m_device->device(), m_commandBuffer->handle(), &rp_begin, false,
                         "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532", nullptr);
     subpass_sample_locations.subpassIndex = 0;
 
@@ -6934,15 +7145,7 @@
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
     PFN_vkCmdNextSubpass2KHR vkCmdNextSubpass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState());
 
     if (rp2Supported) {
@@ -6982,15 +7185,7 @@
 
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
     PFN_vkCmdEndRenderPass2KHR vkCmdEndRenderPass2KHR = nullptr;
-    bool rp2Supported = false;
-
-    // Check for VK_KHR_create_renderpass2
-    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-        m_device_extension_names.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME);
-        m_device_extension_names.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
-        rp2Supported = true;
-    }
+    bool rp2Supported = CheckCreateRenderPass2Support(this, m_device_extension_names);
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
 
     if (rp2Supported) {
@@ -7791,7 +7986,7 @@
     fb_info.attachmentCount = 1;
     fb_info.renderPass = rp_ds;
 
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-pAttachments-00878");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkFramebufferCreateInfo-pAttachments-02633");
     err = vkCreateFramebuffer(device(), &fb_info, NULL, &fb);
 
     m_errorMonitor->VerifyFound();
@@ -8494,73 +8689,29 @@
         "1) A uniform buffer update must have a valid buffer index. "
         "2) When using an array of descriptors in a single WriteDescriptor, the descriptor types and stageflags "
         "must all be the same. "
-        "3) Immutable Sampler state must match across descriptors");
+        "3) Immutable Sampler state must match across descriptors. "
+        "4) That sampled image descriptors have required layouts. ");
 
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-00324");
 
     ASSERT_NO_FATAL_FAILURE(Init());
-    VkDescriptorPoolSize ds_type_count[4] = {};
-    ds_type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-    ds_type_count[0].descriptorCount = 1;
-    ds_type_count[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
-    ds_type_count[1].descriptorCount = 1;
-    ds_type_count[2].type = VK_DESCRIPTOR_TYPE_SAMPLER;
-    ds_type_count[2].descriptorCount = 1;
-    ds_type_count[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
-    ds_type_count[3].descriptorCount = 1;
-
-    VkDescriptorPoolCreateInfo ds_pool_ci = {};
-    ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
-    ds_pool_ci.maxSets = 1;
-    ds_pool_ci.poolSizeCount = sizeof(ds_type_count) / sizeof(VkDescriptorPoolSize);
-    ds_pool_ci.pPoolSizes = ds_type_count;
-
-    VkDescriptorPool ds_pool;
-    VkResult err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool);
-    ASSERT_VK_SUCCESS(err);
-
-    VkDescriptorSetLayoutBinding dslb1 = {};
-    dslb1.binding = 0;
-    dslb1.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-    dslb1.descriptorCount = 1;
-    dslb1.stageFlags = VK_SHADER_STAGE_ALL;
-    dslb1.pImmutableSamplers = NULL;
-
-    VkDescriptorSetLayoutBinding dslb2 = {};
-    dslb2.binding = 1;
-    dslb2.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
-    dslb2.descriptorCount = 1;
-    dslb2.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
-    dslb2.pImmutableSamplers = NULL;
 
     VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
     VkSampler sampler;
-
-    err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler);
+    VkResult err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler);
     ASSERT_VK_SUCCESS(err);
 
-    VkDescriptorSetLayoutBinding dslb3 = {};
-    dslb3.binding = 2;
-    dslb3.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
-    dslb3.descriptorCount = 1;
-    dslb3.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
-    dslb3.pImmutableSamplers = static_cast<VkSampler *>(&sampler);
-
-    const std::vector<VkDescriptorSetLayoutBinding> layout_bindings = {dslb1, dslb2, dslb3};
-    const VkDescriptorSetLayoutObj ds_layout(m_device, layout_bindings);
-
-    VkDescriptorSetAllocateInfo alloc_info = {};
-    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
-    alloc_info.descriptorSetCount = 1;
-    alloc_info.descriptorPool = ds_pool;
-    alloc_info.pSetLayouts = &ds_layout.handle();
-    VkDescriptorSet descriptorSet;
-    err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet);
-    ASSERT_VK_SUCCESS(err);
+    OneOffDescriptorSet::Bindings bindings = {
+        {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL},
+        {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, NULL},
+        {2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, static_cast<VkSampler *>(&sampler)},
+        {3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, NULL}};
+    OneOffDescriptorSet descriptor_set(m_device, bindings);
+    ASSERT_TRUE(descriptor_set.Initialized());
 
     VkWriteDescriptorSet descriptor_write = {};
     descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
-    descriptor_write.dstSet = descriptorSet;
+    descriptor_write.dstSet = descriptor_set.set_;
     descriptor_write.dstBinding = 0;
     descriptor_write.descriptorCount = 1;
     descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -8624,10 +8775,28 @@
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
     m_errorMonitor->VerifyFound();
 
+    // 4) That sampled image descriptors have required layouts
+    // Create images to update the descriptor with
+    VkImageObj image(m_device);
+    const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
+    image.Init(32, 32, 1, tex_format, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
+    ASSERT_TRUE(image.initialized());
+
+    // Attmept write with incorrect layout for sampled descriptor
+    imageInfo.sampler = VK_NULL_HANDLE;
+    imageInfo.imageView = image.targetView(tex_format);
+    imageInfo.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+    descriptor_write.dstBinding = 3;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-01403");
+    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+    m_errorMonitor->VerifyFound();
+
     vkDestroyBuffer(m_device->device(), dyub, NULL);
     vkFreeMemory(m_device->device(), mem, NULL);
     vkDestroySampler(m_device->device(), sampler, NULL);
-    vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL);
 }
 
 TEST_F(VkLayerTest, WriteDescriptorSetConsecutiveUpdates) {
@@ -10282,7 +10451,9 @@
     memory_info.memoryTypeIndex = 0;
     vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs);
     // Allocate enough memory for both images
-    memory_info.allocationSize = memory_reqs.size * 2;
+    VkDeviceSize align_mod = memory_reqs.size % memory_reqs.alignment;
+    VkDeviceSize aligned_size = ((align_mod == 0) ? memory_reqs.size : (memory_reqs.size + memory_reqs.alignment - align_mod));
+    memory_info.allocationSize = aligned_size * 2;
     pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0);
     ASSERT_TRUE(pass);
     err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &image_memory);
@@ -10290,7 +10461,7 @@
     err = vkBindImageMemory(m_device->device(), image, image_memory, 0);
     ASSERT_VK_SUCCESS(err);
     // Bind second image to memory right after first image
-    err = vkBindImageMemory(m_device->device(), image2, image_memory, memory_reqs.size);
+    err = vkBindImageMemory(m_device->device(), image2, image_memory, aligned_size);
     ASSERT_VK_SUCCESS(err);
 
     VkImageViewCreateInfo image_view_create_info = {};
@@ -10363,6 +10534,25 @@
 
     // First error case is destroying sampler prior to cmd buffer submission
     m_commandBuffer->begin();
+
+    // Transit image layout from VK_IMAGE_LAYOUT_UNDEFINED into VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+    VkImageMemoryBarrier barrier = {};
+    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    barrier.image = image;
+    barrier.srcAccessMask = 0;
+    barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+    barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    barrier.subresourceRange.baseMipLevel = 0;
+    barrier.subresourceRange.levelCount = 1;
+    barrier.subresourceRange.baseArrayLayer = 0;
+    barrier.subresourceRange.layerCount = 1;
+    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0,
+                         nullptr, 0, nullptr, 1, &barrier);
+
     m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
     vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
     vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
@@ -10455,6 +10645,12 @@
     img_info.imageView = view2;
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
     m_commandBuffer->begin(&info);
+
+    // Transit image2 layout from VK_IMAGE_LAYOUT_UNDEFINED into VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+    barrier.image = image2;
+    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0,
+                         nullptr, 0, nullptr, 1, &barrier);
+
     m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
     vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
     vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
@@ -10718,9 +10914,8 @@
     vkCmdSetScissor(cmd_buf.handle(), 0, 1, &scissor);
     // At draw time the update layout will mis-match the actual layout
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDescriptorImageInfo-imageLayout-00344");
-    m_errorMonitor->SetDesiredFailureMsg(
-        VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        " Image layout specified at vkUpdateDescriptorSets() time doesn't match actual image layout at time descriptor is used.");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "UNASSIGNED-CoreValidation-DrawState-DescriptorSetNotUpdated");
     cmd_buf.Draw(1, 0, 0, 0);
     m_errorMonitor->VerifyFound();
     cmd_buf.EndRenderPass();
@@ -11275,14 +11470,16 @@
         ASSERT_NE(fpCmdDrawIndirectCountKHR, nullptr);
 
         m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndirectCountKHR-None-03119");
-        fpCmdDrawIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 0);
+        // stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndirectCommand)
+        fpCmdDrawIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
         m_errorMonitor->VerifyFound();
 
         auto fpCmdDrawIndexedIndirectCountKHR =
             (PFN_vkCmdDrawIndexedIndirectCountKHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdDrawIndexedIndirectCountKHR");
         ASSERT_NE(fpCmdDrawIndexedIndirectCountKHR, nullptr);
         m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawIndexedIndirectCountKHR-None-03151");
-        fpCmdDrawIndexedIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 0);
+        // stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndexedIndirectCommand)
+        fpCmdDrawIndexedIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
         m_errorMonitor->VerifyFound();
     }
 
@@ -11555,71 +11752,6 @@
     vkDestroyImage(device(), image, NULL);
 }
 
-TEST_F(VkLayerTest, DescriptorSetNotUpdated) {
-    TEST_DESCRIPTION("Bind a descriptor set that hasn't been updated.");
-    VkResult err;
-
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, " bound but it was never updated. ");
-
-    ASSERT_NO_FATAL_FAILURE(Init());
-    ASSERT_NO_FATAL_FAILURE(InitViewport());
-    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
-    VkDescriptorPoolSize ds_type_count = {};
-    ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-    ds_type_count.descriptorCount = 1;
-
-    VkDescriptorPoolCreateInfo ds_pool_ci = {};
-    ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
-    ds_pool_ci.pNext = NULL;
-    ds_pool_ci.maxSets = 1;
-    ds_pool_ci.poolSizeCount = 1;
-    ds_pool_ci.pPoolSizes = &ds_type_count;
-
-    VkDescriptorPool ds_pool;
-    err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool);
-    ASSERT_VK_SUCCESS(err);
-
-    VkDescriptorSetLayoutBinding dsl_binding = {};
-    dsl_binding.binding = 0;
-    dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-    dsl_binding.descriptorCount = 1;
-    dsl_binding.stageFlags = VK_SHADER_STAGE_ALL;
-    dsl_binding.pImmutableSamplers = NULL;
-
-    const VkDescriptorSetLayoutObj ds_layout(m_device, {dsl_binding});
-
-    VkDescriptorSet descriptorSet;
-    VkDescriptorSetAllocateInfo alloc_info = {};
-    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
-    alloc_info.descriptorSetCount = 1;
-    alloc_info.descriptorPool = ds_pool;
-    alloc_info.pSetLayouts = &ds_layout.handle();
-    err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet);
-    ASSERT_VK_SUCCESS(err);
-
-    const VkPipelineLayoutObj pipeline_layout(m_device, {&ds_layout});
-
-    VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this);
-    //  We shouldn't need a fragment shader but add it to be able to run
-    //  on more devices
-    VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this);
-
-    VkPipelineObj pipe(m_device);
-    pipe.AddShader(&vs);
-    pipe.AddShader(&fs);
-    pipe.AddDefaultColorAttachment();
-    pipe.CreateVKPipeline(pipeline_layout.handle(), renderPass());
-
-    m_commandBuffer->begin();
-    vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
-    vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
-                            &descriptorSet, 0, NULL);
-
-    m_errorMonitor->VerifyFound();
-
-    vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL);
-}
-
 TEST_F(VkLayerTest, InvalidBufferViewObject) {
     // Create a single TEXEL_BUFFER descriptor and send it an invalid bufferView
     // First, cause the bufferView to be invalid due to underlying buffer being destroyed
@@ -11844,7 +11976,7 @@
     buff_view_ci.range = 0;
     CatchError("VUID-VkBufferViewCreateInfo-range-00928");
 
-    size_t format_size = FormatSize(buff_view_ci.format);
+    uint32_t format_size = FormatElementSize(buff_view_ci.format);
     // Range must be a multiple of the element size of format, so add one to ensure it is not
     buff_view_ci.range = format_size + 1;
     CatchError("VUID-VkBufferViewCreateInfo-range-00929");
@@ -12802,10 +12934,15 @@
 
 TEST_F(VkLayerTest, InvalidPipelineSamplePNext) {
     // Enable sample shading in pipeline when the feature is disabled.
+    // Check for VK_KHR_get_physical_device_properties2
+    if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
 
     // Set up the extension structs
     auto sampleLocations = chain_util::Init<VkPipelineSampleLocationsStateCreateInfoEXT>();
+    sampleLocations.sampleLocationsInfo.sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT;
     auto coverageToColor = chain_util::Init<VkPipelineCoverageToColorStateCreateInfoNV>();
     auto coverageModulation = chain_util::Init<VkPipelineCoverageModulationStateCreateInfoNV>();
     auto discriminatrix = [this](const char *name) { return DeviceExtensionSupported(gpu(), nullptr, name); };
@@ -12832,6 +12969,196 @@
                                       "VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext");
 }
 
+TEST_F(VkLayerTest, VertexAttributeDivisorExtension) {
+    TEST_DESCRIPTION("Test VUIDs added with VK_EXT_vertex_attribute_divisor extension.");
+
+    bool inst_ext = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    if (inst_ext) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    }
+    if (inst_ext && DeviceExtensionSupported(gpu(), nullptr, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+        return;
+    }
+
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vadf = {};
+    vadf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+    vadf.vertexAttributeInstanceRateDivisor = VK_TRUE;
+    vadf.vertexAttributeInstanceRateZeroDivisor = VK_TRUE;
+
+    VkPhysicalDeviceFeatures2 pd_features2 = {};
+    pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    pd_features2.pNext = &vadf;
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    const VkPhysicalDeviceLimits &dev_limits = m_device->props.limits;
+    VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT pdvad_props = {};
+    pdvad_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
+    VkPhysicalDeviceProperties2 pd_props2 = {};
+    pd_props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+    pd_props2.pNext = &pdvad_props;
+    vkGetPhysicalDeviceProperties2(gpu(), &pd_props2);
+
+    VkVertexInputBindingDivisorDescriptionEXT vibdd = {};
+    VkPipelineVertexInputDivisorStateCreateInfoEXT pvids_ci = {};
+    pvids_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
+    pvids_ci.vertexBindingDivisorCount = 1;
+    pvids_ci.pVertexBindingDivisors = &vibdd;
+    VkVertexInputBindingDescription vibd = {};
+    vibd.stride = 12;
+    vibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+    using std::vector;
+    struct TestCase {
+        uint32_t div_binding;
+        uint32_t div_divisor;
+        uint32_t desc_binding;
+        VkVertexInputRate desc_rate;
+        vector<std::string> vuids;
+    };
+
+    // clang-format off
+    vector<TestCase> test_cases = {
+        {   0, 
+            1, 
+            0, 
+            VK_VERTEX_INPUT_RATE_VERTEX, 
+            {"VUID-VkVertexInputBindingDivisorDescriptionEXT-inputRate-01871"}
+        },
+        {   dev_limits.maxVertexInputBindings + 1,
+            1,
+            0,
+            VK_VERTEX_INPUT_RATE_INSTANCE,
+            {"VUID-VkVertexInputBindingDivisorDescriptionEXT-binding-01869",
+             "VUID-VkVertexInputBindingDivisorDescriptionEXT-inputRate-01871"}
+        }
+    };
+
+    if (UINT32_MAX != pdvad_props.maxVertexAttribDivisor) {  // Can't test overflow if maxVAD is UINT32_MAX
+        test_cases.push_back(
+            {   0,
+                pdvad_props.maxVertexAttribDivisor + 1,
+                0,
+                VK_VERTEX_INPUT_RATE_INSTANCE,
+                {"VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870"}
+            } );
+    }
+    // clang-format on
+
+    for (const auto &test_case : test_cases) {
+        const auto bad_divisor_state = [&test_case, &vibdd, &pvids_ci, &vibd](CreatePipelineHelper &helper) {
+            vibdd.binding = test_case.div_binding;
+            vibdd.divisor = test_case.div_divisor;
+            vibd.binding = test_case.desc_binding;
+            vibd.inputRate = test_case.desc_rate;
+            helper.vi_ci_.pNext = &pvids_ci;
+            helper.vi_ci_.vertexBindingDescriptionCount = 1;
+            helper.vi_ci_.pVertexBindingDescriptions = &vibd;
+        };
+        CreatePipelineHelper::OneshotTest(*this, bad_divisor_state, VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuids);
+    }
+}
+
+TEST_F(VkLayerTest, VertexAttributeDivisorDisabled) {
+    TEST_DESCRIPTION("Test instance divisor feature disabled for VK_EXT_vertex_attribute_divisor extension.");
+
+    bool inst_ext = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    if (inst_ext) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    }
+    if (inst_ext && DeviceExtensionSupported(gpu(), nullptr, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+        return;
+    }
+
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vadf = {};
+    vadf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+    vadf.vertexAttributeInstanceRateDivisor = VK_FALSE;
+    vadf.vertexAttributeInstanceRateZeroDivisor = VK_FALSE;
+    VkPhysicalDeviceFeatures2 pd_features2 = {};
+    pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    pd_features2.pNext = &vadf;
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkVertexInputBindingDivisorDescriptionEXT vibdd = {};
+    vibdd.binding = 0;
+    vibdd.divisor = 2;
+    VkPipelineVertexInputDivisorStateCreateInfoEXT pvids_ci = {};
+    pvids_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
+    pvids_ci.vertexBindingDivisorCount = 1;
+    pvids_ci.pVertexBindingDivisors = &vibdd;
+    VkVertexInputBindingDescription vibd = {};
+    vibd.binding = vibdd.binding;
+    vibd.stride = 12;
+    vibd.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
+
+    const auto instance_rate = [&pvids_ci, &vibd](CreatePipelineHelper &helper) {
+        helper.vi_ci_.pNext = &pvids_ci;
+        helper.vi_ci_.vertexBindingDescriptionCount = 1;
+        helper.vi_ci_.pVertexBindingDescriptions = &vibd;
+    };
+    CreatePipelineHelper::OneshotTest(*this, instance_rate, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                      "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229");
+}
+
+TEST_F(VkLayerTest, VertexAttributeDivisorInstanceRateZero) {
+    TEST_DESCRIPTION("Test instanceRateZero feature of VK_EXT_vertex_attribute_divisor extension.");
+
+    bool inst_ext = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    if (inst_ext) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    }
+    if (inst_ext && DeviceExtensionSupported(gpu(), nullptr, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+        return;
+    }
+
+    VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vadf = {};
+    vadf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+    vadf.vertexAttributeInstanceRateDivisor = VK_TRUE;
+    vadf.vertexAttributeInstanceRateZeroDivisor = VK_FALSE;
+    VkPhysicalDeviceFeatures2 pd_features2 = {};
+    pd_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    pd_features2.pNext = &vadf;
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &pd_features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkVertexInputBindingDivisorDescriptionEXT vibdd = {};
+    vibdd.binding = 0;
+    vibdd.divisor = 0;
+    VkPipelineVertexInputDivisorStateCreateInfoEXT pvids_ci = {};
+    pvids_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
+    pvids_ci.vertexBindingDivisorCount = 1;
+    pvids_ci.pVertexBindingDivisors = &vibdd;
+    VkVertexInputBindingDescription vibd = {};
+    vibd.binding = vibdd.binding;
+    vibd.stride = 12;
+    vibd.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
+
+    const auto instance_rate = [&pvids_ci, &vibd](CreatePipelineHelper &helper) {
+        helper.vi_ci_.pNext = &pvids_ci;
+        helper.vi_ci_.vertexBindingDescriptionCount = 1;
+        helper.vi_ci_.pVertexBindingDescriptions = &vibd;
+    };
+    CreatePipelineHelper::OneshotTest(
+        *this, instance_rate, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228");
+}
+
 /*// TODO : This test should be good, but needs Tess support in compiler to run
 TEST_F(VkLayerTest, InvalidPatchControlPoints)
 {
@@ -14278,7 +14605,6 @@
 
     VkClearColorValue clear_color;
     memset(clear_color.uint32, 0, sizeof(uint32_t) * 4);
-    VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
     const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
     const int32_t tex_width = 32;
     const int32_t tex_height = 32;
@@ -14293,11 +14619,11 @@
     image_create_info.mipLevels = 1;
     image_create_info.arrayLayers = 1;
     image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
-    image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 
     vk_testing::Image dstImage;
-    dstImage.init(*m_device, (const VkImageCreateInfo &)image_create_info, reqs);
+    dstImage.init(*m_device, (const VkImageCreateInfo &)image_create_info);
 
     const VkImageSubresourceRange range = vk_testing::Image::subresource_range(image_create_info, VK_IMAGE_ASPECT_COLOR_BIT);
 
@@ -15591,7 +15917,7 @@
 }
 
 TEST_F(VkLayerTest, InvalidQueueFamilyIndex) {
-    // Create an out-of-range queueFamilyIndex
+    // Miscellaneous queueFamilyIndex validation tests
     ASSERT_NO_FATAL_FAILURE(Init());
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
     VkBufferCreateInfo buffCI = {};
@@ -15608,9 +15934,14 @@
     buffCI.sharingMode = VK_SHARING_MODE_CONCURRENT;  // qfi only matters in CONCURRENT mode
 
     VkBuffer ib;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                         "vkCreateBuffer: pCreateInfo->pQueueFamilyIndices[0] (= 777) is not one of the queue "
-                                         "families given via VkDeviceQueueCreateInfo structures when the device was created.");
+    // Test for queue family index out of range
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferCreateInfo-sharingMode-01419");
+    vkCreateBuffer(m_device->device(), &buffCI, NULL, &ib);
+    m_errorMonitor->VerifyFound();
+
+    // Test for non-unique QFI in array
+    qfi[0] = 0;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferCreateInfo-sharingMode-01419");
     vkCreateBuffer(m_device->device(), &buffCI, NULL, &ib);
     m_errorMonitor->VerifyFound();
 
@@ -15785,10 +16116,35 @@
         "3. range value greater than buffer (size - offset)");
     VkResult err;
 
-    ASSERT_NO_FATAL_FAILURE(Init());
-    OneOffDescriptorSet ds(m_device, {
-                                         {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
-                                     });
+    // GPDDP2 needed for push descriptors support below
+    bool gpdp2_support = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+                                                    VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION);
+    if (gpdp2_support) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    }
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    bool update_template_support = DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
+    if (update_template_support) {
+        m_device_extension_names.push_back(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
+    } else {
+        printf("%s Descriptor Update Template Extensions not supported, template cases skipped.\n", kSkipPrefix);
+    }
+
+    // Note: Includes workaround for some implementations which incorrectly return 0 maxPushDescriptors
+    bool push_descriptor_support = gpdp2_support &&
+                                   DeviceExtensionSupported(gpu(), nullptr, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) &&
+                                   (GetPushDescriptorProperties(instance(), gpu()).maxPushDescriptors > 0);
+    if (push_descriptor_support) {
+        m_device_extension_names.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
+    } else {
+        printf("%s Push Descriptor Extension not supported, push descriptor cases skipped.\n", kSkipPrefix);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
+
+    std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
+        {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
+    OneOffDescriptorSet ds(m_device, ds_bindings);
 
     // Create a buffer to be used for invalid updates
     VkBufferCreateInfo buff_ci = {};
@@ -15823,9 +16179,6 @@
 
     VkDescriptorBufferInfo buff_info = {};
     buff_info.buffer = buffer;
-    // Cause error due to offset out of range
-    buff_info.offset = buff_ci.size;
-    buff_info.range = VK_WHOLE_SIZE;
     VkWriteDescriptorSet descriptor_write = {};
     descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     descriptor_write.dstBinding = 0;
@@ -15836,27 +16189,132 @@
 
     descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
     descriptor_write.dstSet = ds.set_;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDescriptorBufferInfo-offset-00340");
 
-    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+    // Relying on the "return nullptr for non-enabled extensions
+    auto vkCreateDescriptorUpdateTemplateKHR =
+        (PFN_vkCreateDescriptorUpdateTemplateKHR)vkGetDeviceProcAddr(m_device->device(), "vkCreateDescriptorUpdateTemplateKHR");
+    auto vkDestroyDescriptorUpdateTemplateKHR =
+        (PFN_vkDestroyDescriptorUpdateTemplateKHR)vkGetDeviceProcAddr(m_device->device(), "vkDestroyDescriptorUpdateTemplateKHR");
+    auto vkUpdateDescriptorSetWithTemplateKHR =
+        (PFN_vkUpdateDescriptorSetWithTemplateKHR)vkGetDeviceProcAddr(m_device->device(), "vkUpdateDescriptorSetWithTemplateKHR");
 
-    m_errorMonitor->VerifyFound();
+    if (update_template_support) {
+        ASSERT_NE(vkCreateDescriptorUpdateTemplateKHR, nullptr);
+        ASSERT_NE(vkDestroyDescriptorUpdateTemplateKHR, nullptr);
+        ASSERT_NE(vkUpdateDescriptorSetWithTemplateKHR, nullptr);
+    }
+
+    // Setup for update w/ template tests
+    // Create a template of descriptor set updates
+    struct SimpleTemplateData {
+        uint8_t padding[7];
+        VkDescriptorBufferInfo buff_info;
+        uint32_t other_padding[4];
+    };
+    SimpleTemplateData update_template_data = {};
+
+    VkDescriptorUpdateTemplateEntry update_template_entry = {};
+    update_template_entry.dstBinding = 0;
+    update_template_entry.dstArrayElement = 0;
+    update_template_entry.descriptorCount = 1;
+    update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    update_template_entry.offset = offsetof(SimpleTemplateData, buff_info);
+    update_template_entry.stride = sizeof(SimpleTemplateData);
+
+    auto update_template_ci = lvl_init_struct<VkDescriptorUpdateTemplateCreateInfoKHR>();
+    update_template_ci.descriptorUpdateEntryCount = 1;
+    update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
+    update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
+    update_template_ci.descriptorSetLayout = ds.layout_.handle();
+
+    VkDescriptorUpdateTemplate update_template = VK_NULL_HANDLE;
+    if (update_template_support) {
+        auto result = vkCreateDescriptorUpdateTemplateKHR(m_device->device(), &update_template_ci, nullptr, &update_template);
+        ASSERT_VK_SUCCESS(result);
+    }
+
+    // VK_KHR_push_descriptor support
+    auto vkCmdPushDescriptorSetKHR =
+        (PFN_vkCmdPushDescriptorSetKHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdPushDescriptorSetKHR");
+    auto vkCmdPushDescriptorSetWithTemplateKHR =
+        (PFN_vkCmdPushDescriptorSetWithTemplateKHR)vkGetDeviceProcAddr(m_device->device(), "vkCmdPushDescriptorSetWithTemplateKHR");
+
+    std::unique_ptr<VkDescriptorSetLayoutObj> push_dsl = nullptr;
+    std::unique_ptr<VkPipelineLayoutObj> pipeline_layout = nullptr;
+    VkDescriptorUpdateTemplate push_template = VK_NULL_HANDLE;
+    if (push_descriptor_support) {
+        ASSERT_NE(vkCmdPushDescriptorSetKHR, nullptr);
+        push_dsl.reset(
+            new VkDescriptorSetLayoutObj(m_device, ds_bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR));
+        pipeline_layout.reset(new VkPipelineLayoutObj(m_device, {push_dsl.get()}));
+        ASSERT_TRUE(push_dsl->initialized());
+
+        if (update_template_support) {
+            ASSERT_NE(vkCmdPushDescriptorSetWithTemplateKHR, nullptr);
+            auto push_template_ci = lvl_init_struct<VkDescriptorUpdateTemplateCreateInfoKHR>();
+            push_template_ci.descriptorUpdateEntryCount = 1;
+            push_template_ci.pDescriptorUpdateEntries = &update_template_entry;
+            push_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR;
+            push_template_ci.descriptorSetLayout = VK_NULL_HANDLE;
+            push_template_ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+            push_template_ci.pipelineLayout = pipeline_layout->handle();
+            push_template_ci.set = 0;
+            auto result = vkCreateDescriptorUpdateTemplateKHR(m_device->device(), &push_template_ci, nullptr, &push_template);
+            ASSERT_VK_SUCCESS(result);
+        }
+    }
+
+    auto do_test = [&](const char *desired_failure) {
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, desired_failure);
+        vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+        m_errorMonitor->VerifyFound();
+
+        if (push_descriptor_support) {
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, desired_failure);
+            m_commandBuffer->begin();
+            vkCmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout->handle(), 0, 1,
+                                      &descriptor_write);
+            m_commandBuffer->end();
+            m_errorMonitor->VerifyFound();
+        }
+
+        if (update_template_support) {
+            update_template_data.buff_info = buff_info;  // copy the test case information into our "pData"
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, desired_failure);
+            vkUpdateDescriptorSetWithTemplateKHR(m_device->device(), ds.set_, update_template, &update_template_data);
+            m_errorMonitor->VerifyFound();
+            if (push_descriptor_support) {
+                m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, desired_failure);
+                m_commandBuffer->begin();
+                vkCmdPushDescriptorSetWithTemplateKHR(m_commandBuffer->handle(), push_template, pipeline_layout->handle(), 0,
+                                                      &update_template_data);
+                m_commandBuffer->end();
+                m_errorMonitor->VerifyFound();
+            }
+        }
+    };
+
+    // Cause error due to offset out of range
+    buff_info.offset = buff_ci.size;
+    buff_info.range = VK_WHOLE_SIZE;
+    do_test("VUID-VkDescriptorBufferInfo-offset-00340");
+
     // Now cause error due to range of 0
     buff_info.offset = 0;
     buff_info.range = 0;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDescriptorBufferInfo-range-00341");
+    do_test("VUID-VkDescriptorBufferInfo-range-00341");
 
-    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
-
-    m_errorMonitor->VerifyFound();
     // Now cause error due to range exceeding buffer size - offset
     buff_info.offset = 0;
     buff_info.range = buff_ci.size + 1;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkDescriptorBufferInfo-range-00342");
+    do_test("VUID-VkDescriptorBufferInfo-range-00342");
 
-    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
-
-    m_errorMonitor->VerifyFound();
+    if (update_template_support) {
+        vkDestroyDescriptorUpdateTemplateKHR(m_device->device(), update_template, nullptr);
+        if (push_descriptor_support) {
+            vkDestroyDescriptorUpdateTemplateKHR(m_device->device(), push_template, nullptr);
+        }
+    }
     vkFreeMemory(m_device->device(), mem, NULL);
     vkDestroyBuffer(m_device->device(), buffer, NULL);
 }
@@ -16429,6 +16887,8 @@
     pipe.AddShader(&fs);
     pipe.AddDefaultColorAttachment();
     pipe.SetMSAA(&pipe_ms_state_ci);
+
+    m_errorMonitor->SetUnexpectedError("VUID-VkGraphicsPipelineCreateInfo-subpass-00757");
     pipe.CreateVKPipeline(pipeline_layout.handle(), renderPass());
 
     m_commandBuffer->begin();
@@ -16659,7 +17119,7 @@
 TEST_F(VkLayerTest, MissingClearAttachment) {
     TEST_DESCRIPTION("Points to a wrong colorAttachment index in a VkClearAttachment structure passed to vkCmdClearAttachments");
     ASSERT_NO_FATAL_FAILURE(Init());
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdClearAttachments-aspectMask-00015");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdClearAttachments-aspectMask-02501");
 
     VKTriangleTest(BsoFailCmdClearAttachments);
     m_errorMonitor->VerifyFound();
@@ -16724,7 +17184,7 @@
     VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = {};
     pipe_ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
     pipe_ms_state_ci.pNext = NULL;
-    pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
+    pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
     pipe_ms_state_ci.sampleShadingEnable = 0;
     pipe_ms_state_ci.minSampleShading = 1.0;
     pipe_ms_state_ci.pSampleMask = NULL;
@@ -16909,6 +17369,99 @@
     vkDestroyEvent(m_device->device(), event, nullptr);
 }
 
+TEST_F(VkLayerTest, QueryPreciseBit) {
+    TEST_DESCRIPTION("Check for correct Query Precise Bit circumstances.");
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    // These tests require that the device support pipeline statistics query
+    VkPhysicalDeviceFeatures device_features = {};
+    ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features));
+    if (VK_TRUE != device_features.pipelineStatisticsQuery) {
+        printf("%s Test requires unsupported pipelineStatisticsQuery feature. Skipped.\n", kSkipPrefix);
+        return;
+    }
+
+    std::vector<const char *> device_extension_names;
+    auto features = m_device->phy().features();
+
+    // Test for precise bit when query type is not OCCLUSION
+    if (features.occlusionQueryPrecise) {
+        VkEvent event;
+        VkEventCreateInfo event_create_info{};
+        event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+        vkCreateEvent(m_device->handle(), &event_create_info, nullptr, &event);
+
+        m_commandBuffer->begin();
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginQuery-queryType-00800");
+
+        VkQueryPool query_pool;
+        VkQueryPoolCreateInfo query_pool_create_info = {};
+        query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+        query_pool_create_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
+        query_pool_create_info.queryCount = 1;
+        vkCreateQueryPool(m_device->handle(), &query_pool_create_info, nullptr, &query_pool);
+
+        vkCmdResetQueryPool(m_commandBuffer->handle(), query_pool, 0, 1);
+        vkCmdBeginQuery(m_commandBuffer->handle(), query_pool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
+        vkCmdEndQuery(m_commandBuffer->handle(), query_pool, 0);
+        m_errorMonitor->VerifyFound();
+
+        m_commandBuffer->end();
+        vkDestroyQueryPool(m_device->handle(), query_pool, nullptr);
+        vkDestroyEvent(m_device->handle(), event, nullptr);
+    }
+
+    // Test for precise bit when precise feature is not available
+    features.occlusionQueryPrecise = false;
+    VkDeviceObj test_device(0, gpu(), device_extension_names, &features);
+
+    VkCommandPoolCreateInfo pool_create_info{};
+    pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_create_info.queueFamilyIndex = test_device.graphics_queue_node_index_;
+
+    VkCommandPool command_pool;
+    vkCreateCommandPool(test_device.handle(), &pool_create_info, nullptr, &command_pool);
+
+    VkCommandBufferAllocateInfo cmd = {};
+    cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    cmd.pNext = NULL;
+    cmd.commandPool = command_pool;
+    cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    cmd.commandBufferCount = 1;
+
+    VkCommandBuffer cmd_buffer;
+    VkResult err = vkAllocateCommandBuffers(test_device.handle(), &cmd, &cmd_buffer);
+    ASSERT_VK_SUCCESS(err);
+
+    VkEvent event;
+    VkEventCreateInfo event_create_info{};
+    event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+    vkCreateEvent(test_device.handle(), &event_create_info, nullptr, &event);
+
+    VkCommandBufferBeginInfo begin_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
+                                           VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr};
+
+    vkBeginCommandBuffer(cmd_buffer, &begin_info);
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdBeginQuery-queryType-00800");
+
+    VkQueryPool query_pool;
+    VkQueryPoolCreateInfo query_pool_create_info = {};
+    query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+    query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION;
+    query_pool_create_info.queryCount = 1;
+    vkCreateQueryPool(test_device.handle(), &query_pool_create_info, nullptr, &query_pool);
+
+    vkCmdResetQueryPool(cmd_buffer, query_pool, 0, 1);
+    vkCmdBeginQuery(cmd_buffer, query_pool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
+    vkCmdEndQuery(cmd_buffer, query_pool, 0);
+    m_errorMonitor->VerifyFound();
+
+    vkEndCommandBuffer(cmd_buffer);
+    vkDestroyQueryPool(test_device.handle(), query_pool, nullptr);
+    vkDestroyEvent(test_device.handle(), event, nullptr);
+    vkDestroyCommandPool(test_device.handle(), command_pool, nullptr);
+}
+
 TEST_F(VkLayerTest, VertexBufferInvalid) {
     TEST_DESCRIPTION(
         "Submit a command buffer using deleted vertex buffer, delete a buffer twice, use an invalid offset for each buffer type, "
@@ -18443,7 +18996,9 @@
 
     // Try a zero usage field
     usage_ci.usage = 0;
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "vkCreateImageView: Chained VkImageViewUsageCreateInfo usage field must not be 0");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VkImageViewUsageCreateInfo: value of usage must not be 0");
     res = vkCreateImageView(m_device->device(), &ivci, NULL, &imageView);
     m_errorMonitor->VerifyFound();
     if (VK_SUCCESS == res) {
@@ -18462,6 +19017,7 @@
     // Try an illegal bit in usage field
     usage_ci.usage = 0x10000000 | VK_IMAGE_USAGE_SAMPLED_BIT;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewUsageCreateInfo-usage-parameter");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "UNASSIGNED-GeneralParameterError-UnrecognizedValue");
     res = vkCreateImageView(m_device->device(), &ivci, NULL, &imageView);
     m_errorMonitor->VerifyFound();
     if (VK_SUCCESS == res) {
@@ -19757,29 +20313,31 @@
     ASSERT_NO_FATAL_FAILURE(Init());
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
-    char const *vsSource =
-        "#version 450\n"
-        "\n"
-        "layout(xfb_buffer = 1) out;\n"
-        "void main(){\n"
-        "   gl_Position = vec4(1);\n"
-        "}\n";
+    const std::string spv_source = R"(
+                  OpCapability ImageRect
+                  OpEntryPoint Vertex %main "main"
+          %main = OpFunction %void None %3
+                  OpReturn
+                  OpFunctionEnd
+        )";
 
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Capability TransformFeedback is not allowed by Vulkan");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Capability ImageRect is not allowed by Vulkan");
 
     std::vector<unsigned int> spv;
     VkShaderModuleCreateInfo module_create_info;
     VkShaderModule shader_module;
     module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
     module_create_info.pNext = NULL;
-    this->GLSLtoSPV(VK_SHADER_STAGE_VERTEX_BIT, vsSource, spv);
+    ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, spv_source.data(), spv);
     module_create_info.pCode = spv.data();
     module_create_info.codeSize = spv.size() * sizeof(unsigned int);
     module_create_info.flags = 0;
 
-    vkCreateShaderModule(m_device->handle(), &module_create_info, NULL, &shader_module);
-
+    VkResult err = vkCreateShaderModule(m_device->handle(), &module_create_info, NULL, &shader_module);
     m_errorMonitor->VerifyFound();
+    if (err == VK_SUCCESS) {
+        vkDestroyShaderModule(m_device->handle(), shader_module, NULL);
+    }
 }
 
 TEST_F(VkPositiveLayerTest, ShaderRelaxedBlockLayout) {
@@ -19845,6 +20403,284 @@
     }
 }
 
+TEST_F(VkPositiveLayerTest, ShaderScalarBlockLayout) {
+    // This is a positive test, no errors expected
+    // Verifies the ability to scalar block layout rules with a shader that requires them to be relaxed
+    TEST_DESCRIPTION("Create a shader that requires scalar block layout.");
+    // Enable req'd extensions
+    if (!InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        printf("%s Extension %s not supported, skipping this pass. \n", kSkipPrefix,
+               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        return;
+    }
+    m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    // Check for the Scalar Block Layout extension and turn it on if it's available
+    if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME)) {
+        printf("%s Extension %s not supported, skipping this pass. \n", kSkipPrefix, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
+        return;
+    }
+    m_device_extension_names.push_back(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
+
+    PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 =
+        (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR");
+
+    auto scalar_block_features = lvl_init_struct<VkPhysicalDeviceScalarBlockLayoutFeaturesEXT>(NULL);
+    scalar_block_features.scalarBlockLayout = VK_TRUE;
+    auto query_features2 = lvl_init_struct<VkPhysicalDeviceFeatures2>(&scalar_block_features);
+    vkGetPhysicalDeviceFeatures2(gpu(), &query_features2);
+
+    auto set_features2 = lvl_init_struct<VkPhysicalDeviceFeatures2>(&scalar_block_features);
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &set_features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    // Vertex shader requiring scalar layout.
+    // Without scalar layout, we would expect a message like:
+    // "Structure id 2 decorated as Block for variable in Uniform storage class
+    // must follow standard uniform buffer layout rules: member 1 at offset 4 is not aligned to 16"
+
+    const std::string spv_source = R"(
+                  OpCapability Shader
+                  OpMemoryModel Logical GLSL450
+                  OpEntryPoint Vertex %main "main"
+                  OpSource GLSL 450
+                  OpMemberDecorate %S 0 Offset 0
+                  OpMemberDecorate %S 1 Offset 4
+                  OpMemberDecorate %S 2 Offset 8
+                  OpDecorate %S Block
+                  OpDecorate %B DescriptorSet 0
+                  OpDecorate %B Binding 0
+          %void = OpTypeVoid
+             %3 = OpTypeFunction %void
+         %float = OpTypeFloat 32
+       %v3float = OpTypeVector %float 3
+             %S = OpTypeStruct %float %float %v3float
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+             %B = OpVariable %_ptr_Uniform_S Uniform
+          %main = OpFunction %void None %3
+             %5 = OpLabel
+                  OpReturn
+                  OpFunctionEnd
+        )";
+
+    std::vector<unsigned int> spv;
+    VkShaderModuleCreateInfo module_create_info;
+    VkShaderModule shader_module;
+    module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    module_create_info.pNext = NULL;
+    ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, spv_source.data(), spv);
+    module_create_info.pCode = spv.data();
+    module_create_info.codeSize = spv.size() * sizeof(unsigned int);
+    module_create_info.flags = 0;
+
+    m_errorMonitor->ExpectSuccess();
+    VkResult err = vkCreateShaderModule(m_device->handle(), &module_create_info, NULL, &shader_module);
+    m_errorMonitor->VerifyNotFound();
+    if (err == VK_SUCCESS) {
+        vkDestroyShaderModule(m_device->handle(), shader_module, NULL);
+    }
+}
+
+TEST_F(VkPositiveLayerTest, SpirvGroupDecorations) {
+    TEST_DESCRIPTION("Test shader validation support for group decorations.");
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    const std::string spv_source = R"(
+              OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 430
+               OpName %main "main"
+               OpName %gl_GlobalInvocationID "gl_GlobalInvocationID"
+               OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+               OpDecorate %_runtimearr_float ArrayStride 4
+               OpDecorate %4 BufferBlock
+               OpDecorate %5 Offset 0
+          %4 = OpDecorationGroup
+          %5 = OpDecorationGroup
+               OpGroupDecorate %4 %_struct_6 %_struct_7 %_struct_8 %_struct_9 %_struct_10 %_struct_11
+               OpGroupMemberDecorate %5 %_struct_6 0 %_struct_7 0 %_struct_8 0 %_struct_9 0 %_struct_10 0 %_struct_11 0
+               OpDecorate %12 DescriptorSet 0
+               OpDecorate %13 DescriptorSet 0
+               OpDecorate %13 NonWritable
+               OpDecorate %13 Restrict
+         %14 = OpDecorationGroup
+         %12 = OpDecorationGroup
+         %13 = OpDecorationGroup
+               OpGroupDecorate %12 %15
+               OpGroupDecorate %12 %15
+               OpGroupDecorate %12 %15
+               OpDecorate %15 DescriptorSet 0
+               OpDecorate %15 Binding 5
+               OpGroupDecorate %14 %16
+               OpDecorate %16 DescriptorSet 0
+               OpDecorate %16 Binding 0
+               OpGroupDecorate %12 %17
+               OpDecorate %17 Binding 1
+               OpGroupDecorate %13 %18 %19
+               OpDecorate %18 Binding 2
+               OpDecorate %19 Binding 3
+               OpGroupDecorate %14 %20
+               OpGroupDecorate %12 %20
+               OpGroupDecorate %13 %20
+               OpDecorate %20 Binding 4
+       %bool = OpTypeBool
+       %void = OpTypeVoid
+         %23 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+     %v3uint = OpTypeVector %uint 3
+    %v3float = OpTypeVector %float 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_runtimearr_int = OpTypeRuntimeArray %int
+%_runtimearr_float = OpTypeRuntimeArray %float
+%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+      %int_0 = OpConstant %int 0
+  %_struct_6 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
+         %15 = OpVariable %_ptr_Uniform__struct_6 Uniform
+  %_struct_7 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
+         %16 = OpVariable %_ptr_Uniform__struct_7 Uniform
+  %_struct_8 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_8 = OpTypePointer Uniform %_struct_8
+         %17 = OpVariable %_ptr_Uniform__struct_8 Uniform
+  %_struct_9 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
+         %18 = OpVariable %_ptr_Uniform__struct_9 Uniform
+ %_struct_10 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
+         %19 = OpVariable %_ptr_Uniform__struct_10 Uniform
+ %_struct_11 = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
+         %20 = OpVariable %_ptr_Uniform__struct_11 Uniform
+       %main = OpFunction %void None %23
+         %40 = OpLabel
+         %41 = OpLoad %v3uint %gl_GlobalInvocationID
+         %42 = OpCompositeExtract %uint %41 0
+         %43 = OpAccessChain %_ptr_Uniform_float %16 %int_0 %42
+         %44 = OpAccessChain %_ptr_Uniform_float %17 %int_0 %42
+         %45 = OpAccessChain %_ptr_Uniform_float %18 %int_0 %42
+         %46 = OpAccessChain %_ptr_Uniform_float %19 %int_0 %42
+         %47 = OpAccessChain %_ptr_Uniform_float %20 %int_0 %42
+         %48 = OpAccessChain %_ptr_Uniform_float %15 %int_0 %42
+         %49 = OpLoad %float %43
+         %50 = OpLoad %float %44
+         %51 = OpLoad %float %45
+         %52 = OpLoad %float %46
+         %53 = OpLoad %float %47
+         %54 = OpFAdd %float %49 %50
+         %55 = OpFAdd %float %54 %51
+         %56 = OpFAdd %float %55 %52
+         %57 = OpFAdd %float %56 %53
+               OpStore %48 %57
+               OpReturn
+               OpFunctionEnd
+)";
+
+    // CreateDescriptorSetLayout
+    VkDescriptorSetLayoutBinding dslb[6] = {};
+    for (auto i = 0; i < 6; i++) {
+        dslb[i].binding = i;
+        dslb[i].descriptorCount = 1;
+        dslb[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+        dslb[i].pImmutableSamplers = NULL;
+        dslb[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_ALL;
+    }
+
+    VkDescriptorSetLayoutCreateInfo ds_layout_ci = {};
+    ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    ds_layout_ci.flags = 0;
+    ds_layout_ci.bindingCount = 6;
+    ds_layout_ci.pBindings = dslb;
+
+    VkDescriptorSetLayout ds_layout = {};
+    vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout);
+
+    // CreatePipelineLayout
+    VkPipelineLayoutCreateInfo pipeline_layout_ci = {};
+    pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipeline_layout_ci.pNext = NULL;
+    pipeline_layout_ci.flags = 0;
+    pipeline_layout_ci.setLayoutCount = 1;
+    pipeline_layout_ci.pSetLayouts = &ds_layout;
+    VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
+    vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout);
+
+    // Create DescriptorPool
+    VkDescriptorPoolSize ds_type_count = {};
+    ds_type_count.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+    ds_type_count.descriptorCount = 6;
+
+    VkDescriptorPoolCreateInfo ds_pool_ci = {};
+    ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    ds_pool_ci.pNext = NULL;
+    ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
+    ds_pool_ci.maxSets = 1;
+    ds_pool_ci.poolSizeCount = 1;
+    ds_pool_ci.pPoolSizes = &ds_type_count;
+
+    VkDescriptorPool ds_pool = VK_NULL_HANDLE;
+    vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool);
+
+    // AllocateDescriptorSets
+    VkDescriptorSetAllocateInfo ds_alloc_info = {};
+    ds_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    ds_alloc_info.descriptorSetCount = 1;
+    ds_alloc_info.descriptorPool = ds_pool;
+    ds_alloc_info.pSetLayouts = &ds_layout;
+
+    VkDescriptorSet descriptorSet;
+    vkAllocateDescriptorSets(m_device->device(), &ds_alloc_info, &descriptorSet);
+
+    // CreateShaderModule
+    std::vector<unsigned int> spv;
+    VkShaderModuleCreateInfo module_create_info;
+    VkShaderModule shader_module;
+    module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    module_create_info.pNext = NULL;
+    ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, spv_source.data(), spv);
+    module_create_info.pCode = spv.data();
+    module_create_info.codeSize = spv.size() * sizeof(unsigned int);
+    module_create_info.flags = 0;
+    vkCreateShaderModule(m_device->handle(), &module_create_info, NULL, &shader_module);
+
+    // CreateComputePipelines
+    VkComputePipelineCreateInfo pipeline_info = {};
+    pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+    pipeline_info.pNext = nullptr;
+    pipeline_info.flags = 0;
+    pipeline_info.layout = pipeline_layout;
+    pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
+    pipeline_info.basePipelineIndex = -1;
+    pipeline_info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    pipeline_info.stage.pNext = nullptr;
+    pipeline_info.stage.flags = 0;
+    pipeline_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+    pipeline_info.stage.module = shader_module;
+    pipeline_info.stage.pName = "main";
+    pipeline_info.stage.pSpecializationInfo = nullptr;
+    VkPipeline cs_pipeline;
+
+    m_errorMonitor->ExpectSuccess();
+    vkCreateComputePipelines(device(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &cs_pipeline);
+    m_errorMonitor->VerifyNotFound();
+
+    vkDestroyPipeline(device(), cs_pipeline, nullptr);
+    vkDestroyShaderModule(device(), shader_module, nullptr);
+    vkDestroyDescriptorPool(device(), ds_pool, nullptr);
+    vkDestroyPipelineLayout(device(), pipeline_layout, nullptr);
+    vkDestroyDescriptorSetLayout(device(), ds_layout, nullptr);
+}
+
 TEST_F(VkPositiveLayerTest, CreatePipelineCheckShaderCapabilityExtension1of2) {
     // This is a positive test, no errors expected
     // Verifies the ability to deal with a shader that declares a non-unique SPIRV capability ID
@@ -20886,6 +21722,7 @@
     descriptorSet.AppendDummy();
     descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
 
+    m_errorMonitor->SetUnexpectedError("VUID-VkPipelineVertexInputStateCreateInfo-pVertexBindingDescriptions-00616 ");
     pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
 
     m_errorMonitor->VerifyFound();
@@ -21016,6 +21853,145 @@
     m_errorMonitor->VerifyFound();
 }
 
+TEST_F(VkLayerTest, CreatePipelineFragmentOutputNotConsumedButAlphaToCoverageEnabled) {
+    TEST_DESCRIPTION(
+        "Test that no warning is produced when writing to non-existing color attachment if alpha to coverage is enabled.");
+
+    m_errorMonitor->ExpectSuccess(VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT);
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    char const *vsSource =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "   gl_Position = vec4(1);\n"
+        "}\n";
+    char const *fsSource =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 x;\n"
+        "void main(){\n"
+        "   x = vec4(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+
+    VkPipelineMultisampleStateCreateInfo ms_state_ci = {};
+    ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+    ms_state_ci.alphaToCoverageEnable = VK_TRUE;
+    pipe.SetMSAA(&ms_state_ci);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget(0u));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyNotFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineFragmentNoOutputLocation0ButAlphaToCoverageEnabled) {
+    TEST_DESCRIPTION("Test that an error is produced when alpha to coverage is enabled but no output at location 0 is declared.");
+
+    m_errorMonitor->SetDesiredFailureMsg(
+        VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        "fragment shader doesn't declare alpha output at location 0 even though alpha to coverage is enabled.");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    char const *vsSource =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "   gl_Position = vec4(1);\n"
+        "}\n";
+    char const *fsSource =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+
+    VkPipelineMultisampleStateCreateInfo ms_state_ci = {};
+    ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+    ms_state_ci.alphaToCoverageEnable = VK_TRUE;
+    pipe.SetMSAA(&ms_state_ci);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget(0u));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineFragmentNoAlphaLocation0ButAlphaToCoverageEnabled) {
+    TEST_DESCRIPTION(
+        "Test that an error is produced when alpha to coverage is enabled but output at location 0 doesn't have alpha channel.");
+
+    m_errorMonitor->SetDesiredFailureMsg(
+        VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        "fragment shader doesn't declare alpha output at location 0 even though alpha to coverage is enabled.");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    char const *vsSource =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "   gl_Position = vec4(1);\n"
+        "}\n";
+    char const *fsSource =
+        "#version 450\n"
+        "layout(location=0) out vec3 x;\n"
+        "\n"
+        "void main(){\n"
+        "   x = vec3(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+
+    VkPipelineMultisampleStateCreateInfo ms_state_ci = {};
+    ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+    ms_state_ci.alphaToCoverageEnable = VK_TRUE;
+    pipe.SetMSAA(&ms_state_ci);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget(0u));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
 TEST_F(VkLayerTest, CreatePipelineFragmentOutputTypeMismatch) {
     TEST_DESCRIPTION(
         "Test that an error is produced for a mismatch between the fundamental type of an fragment shader output variable, and the "
@@ -21058,6 +22034,507 @@
     m_errorMonitor->VerifyFound();
 }
 
+TEST_F(VkLayerTest, CreatePipelineExceedMaxVertexOutputComponents) {
+    TEST_DESCRIPTION(
+        "Test that an error is produced when the number of output components from the vertex stage exceeds the device limit");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Vertex shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxVertexOutputComponents");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    const uint32_t maxVsOutComp = m_device->props.limits.maxVertexOutputComponents;
+    std::string vsSourceStr = "#version 450\n\n";
+    const uint32_t numVec4 = maxVsOutComp / 4;
+    uint32_t location = 0;
+    for (uint32_t i = 0; i < numVec4; i++) {
+        vsSourceStr += "layout(location=" + std::to_string(location) + ") out vec4 v" + std::to_string(i) + ";\n";
+        location += 1;
+    }
+    const uint32_t remainder = maxVsOutComp % 4;
+    if (remainder != 0) {
+        if (remainder == 1) {
+            vsSourceStr += "layout(location=" + std::to_string(location) + ") out float" + " vn;\n";
+        } else {
+            vsSourceStr += "layout(location=" + std::to_string(location) + ") out vec" + std::to_string(remainder) + " vn;\n";
+        }
+        location += 1;
+    }
+    vsSourceStr += "layout(location=" + std::to_string(location) +
+                   ") out vec4 exceedLimit;\n"
+                   "\n"
+                   "void main(){\n"
+                   "    gl_Position = vec4(1);\n"
+                   "}\n";
+
+    std::string fsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 color;\n"
+        "\n"
+        "void main(){\n"
+        "    color = vec4(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+
+    // Set up CB 0; type is UNORM by default
+    pipe.AddDefaultColorAttachment();
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineExceedMaxTessellationControlInputOutputComponents) {
+    TEST_DESCRIPTION(
+        "Test that errors are produced when the number of per-vertex input and/or output components to the tessellation control "
+        "stage exceeds the device limit");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Tessellation control shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxTessellationControlPerVertexInputComponents");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Tessellation control shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxTessellationControlPerVertexOutputComponents");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    VkPhysicalDeviceFeatures feat;
+    vkGetPhysicalDeviceFeatures(gpu(), &feat);
+    if (!feat.tessellationShader) {
+        printf("%s tessellation shader stage(s) unsupported.\n", kSkipPrefix);
+        return;
+    }
+
+    std::string vsSourceStr =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    // Tessellation control stage
+    std::string tcsSourceStr =
+        "#version 450\n"
+        "\n";
+    // Input components
+    const uint32_t maxTescInComp = m_device->props.limits.maxTessellationControlPerVertexInputComponents;
+    const uint32_t numInVec4 = maxTescInComp / 4;
+    uint32_t inLocation = 0;
+    for (uint32_t i = 0; i < numInVec4; i++) {
+        tcsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 v" + std::to_string(i) + "In[];\n";
+        inLocation += 1;
+    }
+    const uint32_t inRemainder = maxTescInComp % 4;
+    if (inRemainder != 0) {
+        if (inRemainder == 1) {
+            tcsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in float" + " vnIn[];\n";
+        } else {
+            tcsSourceStr +=
+                "layout(location=" + std::to_string(inLocation) + ") in vec" + std::to_string(inRemainder) + " vnIn[];\n";
+        }
+        inLocation += 1;
+    }
+    tcsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 exceedLimitIn[];\n\n";
+    // Output components
+    const uint32_t maxTescOutComp = m_device->props.limits.maxTessellationControlPerVertexOutputComponents;
+    const uint32_t numOutVec4 = maxTescOutComp / 4;
+    uint32_t outLocation = 0;
+    for (uint32_t i = 0; i < numOutVec4; i++) {
+        tcsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 v" + std::to_string(i) + "Out[3];\n";
+        outLocation += 1;
+    }
+    const uint32_t outRemainder = maxTescOutComp % 4;
+    if (outRemainder != 0) {
+        if (outRemainder == 1) {
+            tcsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out float" + " vnOut[3];\n";
+        } else {
+            tcsSourceStr +=
+                "layout(location=" + std::to_string(outLocation) + ") out vec" + std::to_string(outRemainder) + " vnOut[3];\n";
+        }
+        outLocation += 1;
+    }
+    tcsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 exceedLimitOut[3];\n";
+    tcsSourceStr += "layout(vertices=3) out;\n";
+    // Finalize
+    tcsSourceStr +=
+        "\n"
+        "void main(){\n"
+        "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+        "}\n";
+
+    std::string tesSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(triangles) in;"
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    std::string fsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 color;"
+        "\n"
+        "void main(){\n"
+        "    color = vec4(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj tcs(m_device, tcsSourceStr.c_str(), VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this);
+    VkShaderObj tes(m_device, tesSourceStr.c_str(), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this);
+    VkShaderObj fs(m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&tcs);
+    pipe.AddShader(&tes);
+    pipe.AddShader(&fs);
+
+    // Set up CB 0; type is UNORM by default
+    pipe.AddDefaultColorAttachment();
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {};
+    inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    inputAssemblyInfo.pNext = NULL;
+    inputAssemblyInfo.flags = 0;
+    inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+    inputAssemblyInfo.primitiveRestartEnable = VK_FALSE;
+    pipe.SetInputAssembly(&inputAssemblyInfo);
+
+    VkPipelineTessellationStateCreateInfo tessInfo = {};
+    tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+    tessInfo.pNext = NULL;
+    tessInfo.flags = 0;
+    tessInfo.patchControlPoints = 3;
+    pipe.SetTessellation(&tessInfo);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineExceedMaxTessellationEvaluationInputOutputComponents) {
+    TEST_DESCRIPTION(
+        "Test that errors are produced when the number of input and/or output components to the tessellation evaluation stage "
+        "exceeds the device limit");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Tessellation evaluation shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxTessellationEvaluationInputComponents");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Tessellation evaluation shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxTessellationEvaluationOutputComponents");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    VkPhysicalDeviceFeatures feat;
+    vkGetPhysicalDeviceFeatures(gpu(), &feat);
+    if (!feat.tessellationShader) {
+        printf("%s tessellation shader stage(s) unsupported.\n", kSkipPrefix);
+        return;
+    }
+
+    std::string vsSourceStr =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    std::string tcsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout (vertices = 3) out;\n"
+        "\n"
+        "void main(){\n"
+        "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+        "}\n";
+
+    // Tessellation evaluation stage
+    std::string tesSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout (triangles) in;\n"
+        "\n";
+    // Input components
+    const uint32_t maxTeseInComp = m_device->props.limits.maxTessellationEvaluationInputComponents;
+    const uint32_t numInVec4 = maxTeseInComp / 4;
+    uint32_t inLocation = 0;
+    for (uint32_t i = 0; i < numInVec4; i++) {
+        tesSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 v" + std::to_string(i) + "In[];\n";
+        inLocation += 1;
+    }
+    const uint32_t inRemainder = maxTeseInComp % 4;
+    if (inRemainder != 0) {
+        if (inRemainder == 1) {
+            tesSourceStr += "layout(location=" + std::to_string(inLocation) + ") in float" + " vnIn[];\n";
+        } else {
+            tesSourceStr +=
+                "layout(location=" + std::to_string(inLocation) + ") in vec" + std::to_string(inRemainder) + " vnIn[];\n";
+        }
+        inLocation += 1;
+    }
+    tesSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 exceedLimitIn[];\n\n";
+    // Output components
+    const uint32_t maxTeseOutComp = m_device->props.limits.maxTessellationEvaluationOutputComponents;
+    const uint32_t numOutVec4 = maxTeseOutComp / 4;
+    uint32_t outLocation = 0;
+    for (uint32_t i = 0; i < numOutVec4; i++) {
+        tesSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 v" + std::to_string(i) + "Out;\n";
+        outLocation += 1;
+    }
+    const uint32_t outRemainder = maxTeseOutComp % 4;
+    if (outRemainder != 0) {
+        if (outRemainder == 1) {
+            tesSourceStr += "layout(location=" + std::to_string(outLocation) + ") out float" + " vnOut;\n";
+        } else {
+            tesSourceStr +=
+                "layout(location=" + std::to_string(outLocation) + ") out vec" + std::to_string(outRemainder) + " vnOut;\n";
+        }
+        outLocation += 1;
+    }
+    tesSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 exceedLimitOut;\n";
+    // Finalize
+    tesSourceStr +=
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    std::string fsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 color;"
+        "\n"
+        "void main(){\n"
+        "    color = vec4(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj tcs(m_device, tcsSourceStr.c_str(), VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this);
+    VkShaderObj tes(m_device, tesSourceStr.c_str(), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this);
+    VkShaderObj fs(m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&tcs);
+    pipe.AddShader(&tes);
+    pipe.AddShader(&fs);
+
+    // Set up CB 0; type is UNORM by default
+    pipe.AddDefaultColorAttachment();
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {};
+    inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    inputAssemblyInfo.pNext = NULL;
+    inputAssemblyInfo.flags = 0;
+    inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+    inputAssemblyInfo.primitiveRestartEnable = VK_FALSE;
+    pipe.SetInputAssembly(&inputAssemblyInfo);
+
+    VkPipelineTessellationStateCreateInfo tessInfo = {};
+    tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+    tessInfo.pNext = NULL;
+    tessInfo.flags = 0;
+    tessInfo.patchControlPoints = 3;
+    pipe.SetTessellation(&tessInfo);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineExceedMaxGeometryInputOutputComponents) {
+    TEST_DESCRIPTION(
+        "Test that errors are produced when the number of input and/or output components to the geometry stage exceeds the device "
+        "limit");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Geometry shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxGeometryInputComponents");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Geometry shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxGeometryOutputComponents");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    VkPhysicalDeviceFeatures feat;
+    vkGetPhysicalDeviceFeatures(gpu(), &feat);
+    if (!feat.geometryShader) {
+        printf("%s geometry shader stage unsupported.\n", kSkipPrefix);
+        return;
+    }
+
+    std::string vsSourceStr =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    std::string gsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(triangles) in;\n"
+        "layout(invocations=1) in;\n";
+    // Input components
+    const uint32_t maxGeomInComp = m_device->props.limits.maxGeometryInputComponents;
+    const uint32_t numInVec4 = maxGeomInComp / 4;
+    uint32_t inLocation = 0;
+    for (uint32_t i = 0; i < numInVec4; i++) {
+        gsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 v" + std::to_string(i) + "In[];\n";
+        inLocation += 1;
+    }
+    const uint32_t inRemainder = maxGeomInComp % 4;
+    if (inRemainder != 0) {
+        if (inRemainder == 1) {
+            gsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in float" + " vnIn[];\n";
+        } else {
+            gsSourceStr +=
+                "layout(location=" + std::to_string(inLocation) + ") in vec" + std::to_string(inRemainder) + " vnIn[];\n";
+        }
+        inLocation += 1;
+    }
+    gsSourceStr += "layout(location=" + std::to_string(inLocation) + ") in vec4 exceedLimitIn[];\n\n";
+    // Output components
+    const uint32_t maxGeomOutComp = m_device->props.limits.maxGeometryOutputComponents;
+    const uint32_t numOutVec4 = maxGeomOutComp / 4;
+    uint32_t outLocation = 0;
+    for (uint32_t i = 0; i < numOutVec4; i++) {
+        gsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 v" + std::to_string(i) + "Out;\n";
+        outLocation += 1;
+    }
+    const uint32_t outRemainder = maxGeomOutComp % 4;
+    if (outRemainder != 0) {
+        if (outRemainder == 1) {
+            gsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out float" + " vnOut;\n";
+        } else {
+            gsSourceStr +=
+                "layout(location=" + std::to_string(outLocation) + ") out vec" + std::to_string(outRemainder) + " vnOut;\n";
+        }
+        outLocation += 1;
+    }
+    gsSourceStr += "layout(location=" + std::to_string(outLocation) + ") out vec4 exceedLimitOut;\n";
+    // Finalize
+    gsSourceStr +=
+        "layout(triangle_strip, max_vertices=3) out;\n"
+        "\n"
+        "void main(){\n"
+        "    exceedLimitOut = vec4(1);\n"
+        "}\n";
+
+    std::string fsSourceStr =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 color;"
+        "\n"
+        "void main(){\n"
+        "    color = vec4(1);\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj gs(m_device, gsSourceStr.c_str(), VK_SHADER_STAGE_GEOMETRY_BIT, this);
+    VkShaderObj fs(m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&gs);
+    pipe.AddShader(&fs);
+
+    // Set up CB 0; type is UNORM by default
+    pipe.AddDefaultColorAttachment();
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, CreatePipelineExceedMaxFragmentInputComponents) {
+    TEST_DESCRIPTION(
+        "Test that an error is produced when the number of input components from the fragment stage exceeds the device limit");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "Fragment shader exceeds "
+                                         "VkPhysicalDeviceLimits::maxFragmentInputComponents");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    std::string vsSourceStr =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "    gl_Position = vec4(1);\n"
+        "}\n";
+
+    const uint32_t maxFsInComp = m_device->props.limits.maxFragmentInputComponents;
+    std::string fsSourceStr = "#version 450\n\n";
+    const uint32_t numVec4 = maxFsInComp / 4;
+    uint32_t location = 0;
+    for (uint32_t i = 0; i < numVec4; i++) {
+        fsSourceStr += "layout(location=" + std::to_string(location) + ") in vec4 v" + std::to_string(i) + ";\n";
+        location += 1;
+    }
+    const uint32_t remainder = maxFsInComp % 4;
+    if (remainder != 0) {
+        if (remainder == 1) {
+            fsSourceStr += "layout(location=" + std::to_string(location) + ") in float" + " vn;\n";
+        } else {
+            fsSourceStr += "layout(location=" + std::to_string(location) + ") in vec" + std::to_string(remainder) + " vn;\n";
+        }
+        location += 1;
+    }
+    fsSourceStr += "layout(location=" + std::to_string(location) +
+                   ") in vec4 exceedLimit;\n"
+                   "\n"
+                   "layout(location=0) out vec4 color;"
+                   "\n"
+                   "void main(){\n"
+                   "    color = vec4(1);\n"
+                   "}\n";
+
+    VkShaderObj vs(m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+
+    // Set up CB 0; type is UNORM by default
+    pipe.AddDefaultColorAttachment();
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendDummy();
+    descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass());
+
+    m_errorMonitor->VerifyFound();
+}
+
 TEST_F(VkLayerTest, CreatePipelineUniformBlockNotProvided) {
     TEST_DESCRIPTION(
         "Test that an error is produced for a shader consuming a uniform block which has no corresponding binding in the pipeline "
@@ -21619,7 +23096,7 @@
     image_create_info.mipLevels = 1;
     image_create_info.arrayLayers = 1;
     image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
-    image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
     image_create_info.flags = 0;
 
@@ -21826,8 +23303,7 @@
     image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
     image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
 
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                         "vkCreateImage: VkFormat for image must not be VK_FORMAT_UNDEFINED");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-format-00943");
 
     VkImage image;
     vkCreateImage(m_device->handle(), &image_create_info, NULL, &image);
@@ -22945,9 +24421,9 @@
 
     // Look for NULL-blit warning
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                                         "vkCmdBlitImage: pRegions[0].srcOffsets specify a zero-volume area.");
+                                         "vkCmdBlitImage(): pRegions[0].srcOffsets specify a zero-volume area.");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT,
-                                         "vkCmdBlitImage: pRegions[0].dstOffsets specify a zero-volume area.");
+                                         "vkCmdBlitImage(): pRegions[0].dstOffsets specify a zero-volume area.");
     vkCmdBlitImage(m_commandBuffer->handle(), intImage1.handle(), intImage1.Layout(), intImage2.handle(), intImage2.Layout(), 1,
                    &blitRegion, VK_FILTER_LINEAR);
     m_errorMonitor->VerifyFound();
@@ -24005,6 +25481,126 @@
     m_commandBuffer->end();
 }
 
+TEST_F(VkLayerTest, MultiplaneImageSamplerConversionMismatch) {
+    TEST_DESCRIPTION("Create sampler with ycbcr conversion and use with an image created without ycrcb conversion");
+
+    // Enable KHR multiplane req'd extensions
+    bool mp_extensions = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+                                                    VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION);
+    if (mp_extensions) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    }
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+    mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+    mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+    mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+    if (mp_extensions) {
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+    } else {
+        printf("%s test requires KHR multiplane extensions, not available.  Skipping.\n", kSkipPrefix);
+        return;
+    }
+
+    // Enable Ycbcr Conversion Features
+    VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr_features = {};
+    ycbcr_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+    ycbcr_features.samplerYcbcrConversion = VK_TRUE;
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &ycbcr_features));
+
+    const VkImageCreateInfo ci = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+                                  NULL,
+                                  0,
+                                  VK_IMAGE_TYPE_2D,
+                                  VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR,
+                                  {128, 128, 1},
+                                  1,
+                                  1,
+                                  VK_SAMPLE_COUNT_1_BIT,
+                                  VK_IMAGE_TILING_LINEAR,
+                                  VK_IMAGE_USAGE_SAMPLED_BIT,
+                                  VK_SHARING_MODE_EXCLUSIVE,
+                                  VK_IMAGE_LAYOUT_UNDEFINED};
+
+    // Verify formats
+    bool supported = ImageFormatAndFeaturesSupported(instance(), gpu(), ci, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+    if (!supported) {
+        printf("%s Multiplane image format not supported.  Skipping test.\n", kSkipPrefix);
+        return;
+    }
+
+    // Create Ycbcr conversion
+    VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
+                                                            NULL,
+                                                            VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR,
+                                                            VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
+                                                            VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
+                                                            {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+                                                             VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
+                                                            VK_CHROMA_LOCATION_COSITED_EVEN,
+                                                            VK_CHROMA_LOCATION_COSITED_EVEN,
+                                                            VK_FILTER_NEAREST,
+                                                            false};
+    VkSamplerYcbcrConversion conversion;
+    vkCreateSamplerYcbcrConversion(m_device->handle(), &ycbcr_create_info, nullptr, &conversion);
+    VkSamplerYcbcrConversionInfo ycbcr_info = {};
+    ycbcr_info.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
+    ycbcr_info.conversion = conversion;
+
+    // Create a sampler using conversion
+    VkSamplerCreateInfo sci = SafeSaneSamplerCreateInfo();
+    sci.pNext = &ycbcr_info;
+
+    VkSampler sampler;
+    VkResult err = vkCreateSampler(m_device->device(), &sci, NULL, &sampler);
+    ASSERT_VK_SUCCESS(err);
+
+    // Create an image without a Ycbcr conversion
+    VkImageObj mpimage(m_device);
+    mpimage.init(&ci);
+
+    VkImageView view;
+    VkImageViewCreateInfo ivci = {};
+    ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    ivci.image = mpimage.handle();
+    ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    ivci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR;
+    ivci.subresourceRange.layerCount = 1;
+    ivci.subresourceRange.baseMipLevel = 0;
+    ivci.subresourceRange.levelCount = 1;
+    ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    vkCreateImageView(m_device->device(), &ivci, nullptr, &view);
+
+    // Use the image and sampler together in a descriptor set
+    OneOffDescriptorSet ds(m_device, {
+                                         {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler},
+                                     });
+
+    VkDescriptorImageInfo image_info{};
+    image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    image_info.imageView = view;
+    image_info.sampler = sampler;
+
+    // Update the descriptor set expecting to get an error
+    VkWriteDescriptorSet descriptor_write = {};
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = ds.set_;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_write.pImageInfo = &image_info;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-01948");
+    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+    m_errorMonitor->VerifyFound();
+    vkDestroySamplerYcbcrConversion(m_device->device(), conversion, nullptr);
+    vkDestroyImageView(m_device->device(), view, NULL);
+    vkDestroySampler(m_device->device(), sampler, nullptr);
+}
+
 TEST_F(VkLayerTest, CopyImageMultiplaneAspectBits) {
     // Image copy tests on multiplane images with aspect errors
 
@@ -24091,6 +25687,7 @@
     copy_region.srcOffset = {0, 0, 0};
     copy_region.dstOffset = {0, 0, 0};
 
+    m_errorMonitor->SetUnexpectedError("VUID-vkCmdCopyImage-srcImage-00135");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCopy-srcImage-01552");
     m_commandBuffer->CopyImage(mp2_image.image(), VK_IMAGE_LAYOUT_GENERAL, mp3_image.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
                                &copy_region);
@@ -24105,12 +25702,14 @@
 
     copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT_KHR;
     copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
+    m_errorMonitor->SetUnexpectedError("VUID-vkCmdCopyImage-srcImage-00135");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCopy-dstImage-01554");
     m_commandBuffer->CopyImage(mp3_image.image(), VK_IMAGE_LAYOUT_GENERAL, mp2_image.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
                                &copy_region);
     m_errorMonitor->VerifyFound();
 
     copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    m_errorMonitor->SetUnexpectedError("VUID-vkCmdCopyImage-srcImage-00135");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCopy-dstImage-01555");
     m_commandBuffer->CopyImage(mp2_image.image(), VK_IMAGE_LAYOUT_GENERAL, mp3_image.image(), VK_IMAGE_LAYOUT_GENERAL, 1,
                                &copy_region);
@@ -25346,7 +26945,6 @@
     // Color image
     VkClearColorValue clear_color;
     memset(clear_color.uint32, 0, sizeof(uint32_t) * 4);
-    VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
     const VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
     const int32_t img_width = 32;
     const int32_t img_height = 32;
@@ -25361,21 +26959,20 @@
     image_create_info.mipLevels = 1;
     image_create_info.arrayLayers = 1;
     image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
-    image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
 
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
     vk_testing::Image color_image_no_transfer;
-    color_image_no_transfer.init(*m_device, image_create_info, reqs);
+    color_image_no_transfer.init(*m_device, image_create_info);
 
     image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
     vk_testing::Image color_image;
-    color_image.init(*m_device, image_create_info, reqs);
+    color_image.init(*m_device, image_create_info);
 
     const VkImageSubresourceRange color_range = vk_testing::Image::subresource_range(image_create_info, VK_IMAGE_ASPECT_COLOR_BIT);
 
     // Depth/Stencil image
     VkClearDepthStencilValue clear_value = {0};
-    reqs = 0;  // don't need HOST_VISIBLE DS image
     VkImageCreateInfo ds_image_create_info = vk_testing::Image::create_info();
     ds_image_create_info.imageType = VK_IMAGE_TYPE_2D;
     ds_image_create_info.format = VK_FORMAT_D16_UNORM;
@@ -25385,7 +26982,7 @@
     ds_image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 
     vk_testing::Image ds_image;
-    ds_image.init(*m_device, ds_image_create_info, reqs);
+    ds_image.init(*m_device, ds_image_create_info);
 
     const VkImageSubresourceRange ds_range = vk_testing::Image::subresource_range(ds_image_create_info, VK_IMAGE_ASPECT_DEPTH_BIT);
 
@@ -26747,15 +28344,13 @@
 
     ASSERT_NO_FATAL_FAILURE(InitState());
 
-    // Find address of extension call and make the call
-    PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
-        (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceProperties2KHR");
-    assert(vkGetPhysicalDeviceProperties2KHR != nullptr);
-
     // Get the push descriptor limits
-    auto push_descriptor_prop = lvl_init_struct<VkPhysicalDevicePushDescriptorPropertiesKHR>();
-    auto prop2 = lvl_init_struct<VkPhysicalDeviceProperties2KHR>(&push_descriptor_prop);
-    vkGetPhysicalDeviceProperties2KHR(m_device->phy().handle(), &prop2);
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
 
     VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
 
@@ -26867,10 +28462,11 @@
 
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
 
-    VkDescriptorBindingFlagsEXT flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT;
+    std::array<VkDescriptorBindingFlagsEXT, 2> flags = {VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT,
+                                                        VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT};
     auto flags_create_info = lvl_init_struct<VkDescriptorSetLayoutBindingFlagsCreateInfoEXT>();
-    flags_create_info.bindingCount = 1;
-    flags_create_info.pBindingFlags = &flags;
+    flags_create_info.bindingCount = (uint32_t)flags.size();
+    flags_create_info.pBindingFlags = flags.data();
 
     VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
     auto ds_layout_ci = lvl_init_struct<VkDescriptorSetLayoutCreateInfo>(&flags_create_info);
@@ -26931,7 +28527,7 @@
         ds_layout_ci.flags = 0;
         ds_layout_ci.bindingCount = 1;
         flags_create_info.bindingCount = 1;
-        flags = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT;
+        flags[0] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT;
         err = vkCreateDescriptorSetLayout(m_device->handle(), &ds_layout_ci, nullptr, &ds_layout);
         ASSERT_VK_SUCCESS(err);
 
@@ -27189,6 +28785,13 @@
     }
     ASSERT_NO_FATAL_FAILURE(InitState());
 
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
+
     VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
     auto ds_layout_ci = lvl_init_struct<VkDescriptorSetLayoutCreateInfo>();
     ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
@@ -27240,6 +28843,13 @@
     }
     ASSERT_NO_FATAL_FAILURE(InitState());
 
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
+
     // Create ordinary and push descriptor set layout
     VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
     const VkDescriptorSetLayoutObj ds_layout(m_device, {binding});
@@ -27286,6 +28896,7 @@
 
         m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                              "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-00330");
         if (err_qfi == transfer_only_qfi) {
             // This as this queue neither supports the gfx or compute bindpoints, we'll get two errors
             m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
@@ -27308,6 +28919,7 @@
             // We can't avoid getting *both* errors in this case
             m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                                  "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363");
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-00330");
             m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                                  "VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool");
             vkCmdPushDescriptorSetKHR(tran_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
@@ -27335,6 +28947,7 @@
     // TODO: Add VALIDATION_ERROR_ code support to core_validation::ValidateCmd
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                          "You must call vkBeginCommandBuffer() before this call to vkCmdPushDescriptorSetKHR()");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-00330");
     vkCmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
                               &descriptor_write);
     m_errorMonitor->VerifyFound();
@@ -27545,6 +29158,13 @@
     }
     ASSERT_NO_FATAL_FAILURE(InitState());
 
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
+
     VkDescriptorSetLayoutBinding dsl_binding = {};
     dsl_binding.binding = 0;
     dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -27585,8 +29205,10 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    // Note: Includes workaround for some implementations which incorrectly return 0 maxPushDescriptors
     if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) &&
-        DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME)) {
+        DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME) &&
+        (GetPushDescriptorProperties(instance(), gpu()).maxPushDescriptors > 0)) {
         m_device_extension_names.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
         m_device_extension_names.push_back(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
     } else {
@@ -27681,6 +29303,13 @@
     ASSERT_NO_FATAL_FAILURE(InitState());
     m_errorMonitor->ExpectSuccess();
 
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
+
     VkDescriptorSetLayoutBinding dsl_binding = {};
     dsl_binding.binding = 2;
     dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -27694,7 +29323,7 @@
     const VkPipelineLayoutObj pipeline_layout(m_device, {&ds_layout});
 
     static const float vbo_data[3] = {1.f, 0.f, 1.f};
-    VkConstantBufferObj vbo(m_device, sizeof(vbo_data), (const void *)&vbo_data);
+    VkConstantBufferObj vbo(m_device, sizeof(vbo_data), (const void *)&vbo_data, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
 
     VkDescriptorBufferInfo buff_info;
     buff_info.buffer = vbo.handle();
@@ -27739,6 +29368,14 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitState());
+
+    auto push_descriptor_prop = GetPushDescriptorProperties(instance(), gpu());
+    if (push_descriptor_prop.maxPushDescriptors < 1) {
+        // Some implementations report an invalid maxPushDescriptors of 0
+        printf("%s maxPushDescriptors is zero, skipping tests\n", kSkipPrefix);
+        return;
+    }
+
     ASSERT_NO_FATAL_FAILURE(InitViewport());
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
     m_errorMonitor->ExpectSuccess();
@@ -28612,7 +30249,7 @@
         return;
     }
 
-    m_errorMonitor->ExpectSuccess();
+    m_errorMonitor->ExpectSuccess(VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT);
 
     VkImage image;
     VkImageCreateInfo image_create_info = {};
@@ -28693,6 +30330,101 @@
     m_errorMonitor->VerifyNotFound();
 }
 
+TEST_F(VkPositiveLayerTest, BindSparseMetadata) {
+    TEST_DESCRIPTION("Bind memory for the metadata aspect of a sparse image");
+
+    ASSERT_NO_FATAL_FAILURE(Init());
+
+    auto index = m_device->graphics_queue_node_index_;
+    if (!(m_device->queue_props[index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) {
+        printf("%s Graphics queue does not have sparse binding bit.\n", kSkipPrefix);
+        return;
+    }
+    if (!m_device->phy().features().sparseResidencyImage2D) {
+        printf("%s Device does not support sparse residency for images.\n", kSkipPrefix);
+        return;
+    }
+
+    m_errorMonitor->ExpectSuccess(VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT);
+
+    // Create a sparse image
+    VkImage image;
+    VkImageCreateInfo image_create_info = {};
+    image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_create_info.pNext = NULL;
+    image_create_info.imageType = VK_IMAGE_TYPE_2D;
+    image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM;
+    image_create_info.extent.width = 64;
+    image_create_info.extent.height = 64;
+    image_create_info.extent.depth = 1;
+    image_create_info.mipLevels = 1;
+    image_create_info.arrayLayers = 1;
+    image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
+    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
+    VkResult err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image);
+    ASSERT_VK_SUCCESS(err);
+
+    // Query image memory requirements
+    VkMemoryRequirements memory_reqs;
+    vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs);
+
+    // Query sparse memory requirements
+    uint32_t sparse_reqs_count = 0;
+    vkGetImageSparseMemoryRequirements(m_device->device(), image, &sparse_reqs_count, nullptr);
+    std::vector<VkSparseImageMemoryRequirements> sparse_reqs(sparse_reqs_count);
+    vkGetImageSparseMemoryRequirements(m_device->device(), image, &sparse_reqs_count, sparse_reqs.data());
+
+    // Find requirements for metadata aspect
+    const VkSparseImageMemoryRequirements *metadata_reqs = nullptr;
+    for (auto const &aspect_sparse_reqs : sparse_reqs) {
+        if (aspect_sparse_reqs.formatProperties.aspectMask == VK_IMAGE_ASPECT_METADATA_BIT) {
+            metadata_reqs = &aspect_sparse_reqs;
+        }
+    }
+
+    if (!metadata_reqs) {
+        printf("%s Sparse image does not require memory for metadata.\n", kSkipPrefix);
+    } else {
+        // Allocate memory for the metadata
+        VkDeviceMemory metadata_memory = VK_NULL_HANDLE;
+        VkMemoryAllocateInfo metadata_memory_info = {};
+        metadata_memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+        metadata_memory_info.allocationSize = metadata_reqs->imageMipTailSize;
+        m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &metadata_memory_info, 0);
+        err = vkAllocateMemory(m_device->device(), &metadata_memory_info, NULL, &metadata_memory);
+        ASSERT_VK_SUCCESS(err);
+
+        // Bind metadata
+        VkSparseMemoryBind sparse_bind = {};
+        sparse_bind.resourceOffset = metadata_reqs->imageMipTailOffset;
+        sparse_bind.size = metadata_reqs->imageMipTailSize;
+        sparse_bind.memory = metadata_memory;
+        sparse_bind.memoryOffset = 0;
+        sparse_bind.flags = VK_SPARSE_MEMORY_BIND_METADATA_BIT;
+
+        VkSparseImageOpaqueMemoryBindInfo opaque_bind_info = {};
+        opaque_bind_info.image = image;
+        opaque_bind_info.bindCount = 1;
+        opaque_bind_info.pBinds = &sparse_bind;
+
+        VkBindSparseInfo bind_info = {};
+        bind_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
+        bind_info.imageOpaqueBindCount = 1;
+        bind_info.pImageOpaqueBinds = &opaque_bind_info;
+
+        vkQueueBindSparse(m_device->m_queue, 1, &bind_info, VK_NULL_HANDLE);
+        m_errorMonitor->VerifyNotFound();
+
+        // Cleanup
+        vkQueueWaitIdle(m_device->m_queue);
+        vkFreeMemory(m_device->device(), metadata_memory, NULL);
+    }
+
+    vkDestroyImage(m_device->device(), image, NULL);
+}
+
 TEST_F(VkPositiveLayerTest, FramebufferBindingDestroyCommandPool) {
     TEST_DESCRIPTION(
         "This test should pass. Create a Framebuffer and command buffer, bind them together, then destroy command pool and "
@@ -30994,7 +32726,10 @@
     bool push_descriptor_found = false;
     if (prop2_found && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME)) {
         m_device_extension_names.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
-        push_descriptor_found = true;
+
+        // In addition to the extension being supported we need to have at least one available
+        // Some implementations report an invalid maxPushDescriptors of 0
+        push_descriptor_found = GetPushDescriptorProperties(instance(), gpu()).maxPushDescriptors > 0;
     } else {
         printf("%s %s Extension not supported, skipping push descriptor sub-tests\n", kSkipPrefix,
                VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
@@ -32429,10 +34164,11 @@
 
     // Enable KHR multiplane req'd extensions
     bool mp_extensions = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
-                                                    VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION);
+                                                    VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION);
     if (mp_extensions) {
         m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
     }
+    SetTargetApiVersion(VK_API_VERSION_1_1);
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
     mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
     mp_extensions = mp_extensions && DeviceExtensionSupported(gpu(), nullptr, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
@@ -32448,15 +34184,16 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
     VkImageCreateInfo ci = {};
     ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
     ci.pNext = NULL;
     ci.flags = 0;
     ci.imageType = VK_IMAGE_TYPE_2D;
-    ci.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR;
+    ci.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR;  // All planes of equal extent
     ci.tiling = VK_IMAGE_TILING_OPTIMAL;
-    ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
     ci.extent = {128, 128, 1};
     ci.mipLevels = 1;
     ci.arrayLayers = 1;
@@ -32523,45 +34260,83 @@
     m_commandBuffer->end();
     m_errorMonitor->VerifyNotFound();
 
-#if 0
-    // Copy to/from buffer
-    VkBufferCreateInfo bci = {};
-    bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
-    bci.pNext = NULL;
-    bci.size = 128 * 128 * 3;
-    bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
-    bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-    VkBuffer buffer;
-    ASSERT_VK_SUCCESS(vkCreateBuffer(device(), &bci, NULL, &buffer));
-
-    VkBufferImageCopy copy_region = {};
-    copy_region.bufferRowLength = 128;
-    copy_region.bufferImageHeight = 128;
-    copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT_KHR;
-    copy_region.imageSubresource.layerCount = 1;
-    copy_region.imageExtent.height = 64;
-    copy_region.imageExtent.width = 64;
-    copy_region.imageExtent.depth = 1;
-
-    m_errorMonitor->ExpectSuccess();
-    vkCmdCopyImageToBuffer(m_commandBuffer->handle(), image,VK_IMAGE_LAYOUT_GENERAL, buffer, 1, &copy_region);
-    m_errorMonitor->VerifyNotFound();
-
-    m_errorMonitor->ExpectSuccess();
-    copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
-    vkCmdCopyBufferToImage(m_commandBuffer->handle(), buffer, image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
-    m_errorMonitor->VerifyNotFound();
-#endif
-
     vkFreeMemory(device(), mem_obj, NULL);
     vkDestroyImage(device(), image, NULL);
 
+    // Repeat bind test on a DISJOINT multi-planar image, with per-plane memory objects, using API2 variants
+    //
+    features |= VK_FORMAT_FEATURE_DISJOINT_BIT;
+    ci.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
+    if (ImageFormatAndFeaturesSupported(instance(), gpu(), ci, features)) {
+        ASSERT_VK_SUCCESS(vkCreateImage(device(), &ci, NULL, &image));
+
+        // Allocate & bind memory
+        VkPhysicalDeviceMemoryProperties2 phys_mem_props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2};
+        vkGetPhysicalDeviceMemoryProperties2(gpu(), &phys_mem_props2);
+        VkImagePlaneMemoryRequirementsInfo image_plane_req = {VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO};
+        VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2};
+        mem_req_info2.pNext = &image_plane_req;
+        mem_req_info2.image = image;
+        VkMemoryRequirements2 mem_reqs2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2};
+
+        VkDeviceMemory p0_mem, p1_mem, p2_mem;
+        mem_props = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+        VkMemoryAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
+
+        // Plane 0
+        image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
+        vkGetImageMemoryRequirements2(device(), &mem_req_info2, &mem_reqs2);
+        uint32_t mem_type = 0;
+        for (mem_type = 0; mem_type < phys_mem_props2.memoryProperties.memoryTypeCount; mem_type++) {
+            if ((mem_reqs2.memoryRequirements.memoryTypeBits & (1 << mem_type)) &&
+                ((phys_mem_props2.memoryProperties.memoryTypes[mem_type].propertyFlags & mem_props) == mem_props)) {
+                alloc_info.memoryTypeIndex = mem_type;
+                break;
+            }
+        }
+        alloc_info.allocationSize = mem_reqs2.memoryRequirements.size;
+        ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &alloc_info, NULL, &p0_mem));
+
+        // Plane 1 & 2 use same memory type
+        image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT;
+        vkGetImageMemoryRequirements2(device(), &mem_req_info2, &mem_reqs2);
+        alloc_info.allocationSize = mem_reqs2.memoryRequirements.size;
+        ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &alloc_info, NULL, &p1_mem));
+
+        image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_2_BIT;
+        vkGetImageMemoryRequirements2(device(), &mem_req_info2, &mem_reqs2);
+        alloc_info.allocationSize = mem_reqs2.memoryRequirements.size;
+        ASSERT_VK_SUCCESS(vkAllocateMemory(device(), &alloc_info, NULL, &p2_mem));
+
+        // Set up 3-plane binding
+        VkBindImageMemoryInfo bind_info[3];
+        for (int plane = 0; plane < 3; plane++) {
+            bind_info[plane].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
+            bind_info[plane].pNext = nullptr;
+            bind_info[plane].image = image;
+            bind_info[plane].memoryOffset = 0;
+        }
+        bind_info[0].memory = p0_mem;
+        bind_info[1].memory = p1_mem;
+        bind_info[2].memory = p2_mem;
+
+        m_errorMonitor->ExpectSuccess();
+        vkBindImageMemory2(device(), 3, bind_info);
+        m_errorMonitor->VerifyNotFound();
+
+        vkFreeMemory(device(), p0_mem, NULL);
+        vkFreeMemory(device(), p1_mem, NULL);
+        vkFreeMemory(device(), p2_mem, NULL);
+        vkDestroyImage(device(), image, NULL);
+    }
+
     // Test that changing the layout of ASPECT_COLOR also changes the layout of the individual planes
     VkBufferObj buffer;
     VkMemoryPropertyFlags reqs = 0;
     buffer.init_as_src(*m_device, (VkDeviceSize)128 * 128 * 3, reqs);
     VkImageObj mpimage(m_device);
-    mpimage.Init(256, 256, 1, VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
+    mpimage.Init(256, 256, 1, VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+                 VK_IMAGE_TILING_OPTIMAL, 0);
     VkBufferImageCopy copy_region = {};
     copy_region.bufferRowLength = 128;
     copy_region.bufferImageHeight = 128;
@@ -32579,6 +34354,113 @@
     m_commandBuffer->end();
     m_commandBuffer->QueueCommandBuffer(false);
     m_errorMonitor->VerifyNotFound();
+
+    // Test to verify that views of multiplanar images have layouts tracked correctly
+    // by changing the image's layout then using a view of that image
+    VkImageView view;
+    VkImageViewCreateInfo ivci = {};
+    ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    ivci.image = mpimage.handle();
+    ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    ivci.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR;
+    ivci.subresourceRange.layerCount = 1;
+    ivci.subresourceRange.baseMipLevel = 0;
+    ivci.subresourceRange.levelCount = 1;
+    ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    vkCreateImageView(m_device->device(), &ivci, nullptr, &view);
+
+    OneOffDescriptorSet ds(m_device, {
+                                         {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
+                                     });
+
+    VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
+    VkSampler sampler;
+
+    VkResult err;
+    err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler);
+    ASSERT_VK_SUCCESS(err);
+
+    const VkPipelineLayoutObj pipeline_layout(m_device, {&ds.layout_});
+
+    VkDescriptorImageInfo image_info{};
+    image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    image_info.imageView = view;
+    image_info.sampler = sampler;
+
+    VkWriteDescriptorSet descriptor_write = {};
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = ds.set_;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_write.pImageInfo = &image_info;
+
+    vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+
+    char const *vsSource =
+        "#version 450\n"
+        "\n"
+        "void main(){\n"
+        "   gl_Position = vec4(1);\n"
+        "}\n";
+    char const *fsSource =
+        "#version 450\n"
+        "\n"
+        "layout(set=0, binding=0) uniform sampler2D s;\n"
+        "layout(location=0) out vec4 x;\n"
+        "void main(){\n"
+        "   x = texture(s, vec2(1));\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+    VkPipelineObj pipe(m_device);
+    pipe.AddShader(&vs);
+    pipe.AddShader(&fs);
+    pipe.AddDefaultColorAttachment();
+    pipe.CreateVKPipeline(pipeline_layout.handle(), renderPass());
+
+    m_errorMonitor->ExpectSuccess();
+    m_commandBuffer->begin();
+    VkImageMemoryBarrier img_barrier = {};
+    img_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    img_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+    img_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+    img_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    img_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    img_barrier.image = mpimage.handle();
+    img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    img_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    img_barrier.subresourceRange.baseArrayLayer = 0;
+    img_barrier.subresourceRange.baseMipLevel = 0;
+    img_barrier.subresourceRange.layerCount = 1;
+    img_barrier.subresourceRange.levelCount = 1;
+    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+                         VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &img_barrier);
+    m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
+    vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
+    vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, &ds.set_, 0,
+                            nullptr);
+
+    VkViewport viewport = {0, 0, 16, 16, 0, 1};
+    VkRect2D scissor = {{0, 0}, {16, 16}};
+    vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
+    vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
+
+    m_commandBuffer->Draw(1, 0, 0, 0);
+    m_commandBuffer->EndRenderPass();
+    m_commandBuffer->end();
+    VkSubmitInfo submit_info = {};
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &m_commandBuffer->handle();
+    vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+    m_errorMonitor->VerifyNotFound();
+
+    vkQueueWaitIdle(m_device->m_queue);
+    vkDestroyImageView(m_device->device(), view, NULL);
+    vkDestroySampler(m_device->device(), sampler, nullptr);
 }
 
 TEST_F(VkPositiveLayerTest, ApiVersionZero) {
@@ -32882,8 +34764,7 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    std::array<const char *, 1> required_device_extensions = {
-        {VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME}};
+    std::array<const char *, 1> required_device_extensions = {{VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME}};
     for (auto device_extension : required_device_extensions) {
         if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
             m_device_extension_names.push_back(device_extension);
@@ -32954,8 +34835,8 @@
         };
 
         for (const auto &test_case : test_cases) {
-
-            VkPipelineViewportExclusiveScissorStateCreateInfoNV exc = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV };
+            VkPipelineViewportExclusiveScissorStateCreateInfoNV exc = {
+                VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV};
 
             const auto break_vp = [&test_case, &exc](CreatePipelineHelper &helper) {
                 helper.vp_state_ci_.viewportCount = test_case.viewport_count;
@@ -32981,29 +34862,37 @@
 
         m_commandBuffer->begin();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 1, scissors);
         m_errorMonitor->VerifyFound();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 0, nullptr);
         m_errorMonitor->VerifyFound();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 2, scissors);
         m_errorMonitor->VerifyFound();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 0, scissors);
         m_errorMonitor->VerifyFound();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 2, scissors);
         m_errorMonitor->VerifyFound();
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: required parameter pExclusiveScissors specified as NULL");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "vkCmdSetExclusiveScissorNV: required parameter pExclusiveScissors specified as NULL");
         vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 1, nullptr);
         m_errorMonitor->VerifyFound();
 
@@ -33012,14 +34901,15 @@
             std::string vuid;
         };
 
-        std::vector<TestCase> test_cases = {{{{-1, 0}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
-                                            {{{0, -1}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
-                                            {{{1, 0}, {INT32_MAX, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
-                                            {{{INT32_MAX, 0}, {1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
-                                            {{{0, 0}, {uint32_t{INT32_MAX} + 1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
-                                            {{{0, 1}, {16, INT32_MAX}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
-                                            {{{0, INT32_MAX}, {16, 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
-                                            {{{0, 0}, {16, uint32_t{INT32_MAX} + 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"}};
+        std::vector<TestCase> test_cases = {
+            {{{-1, 0}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
+            {{{0, -1}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
+            {{{1, 0}, {INT32_MAX, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+            {{{INT32_MAX, 0}, {1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+            {{{0, 0}, {uint32_t{INT32_MAX} + 1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+            {{{0, 1}, {16, INT32_MAX}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
+            {{{0, INT32_MAX}, {16, 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
+            {{{0, 0}, {16, uint32_t{INT32_MAX} + 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"}};
 
         for (const auto &test_case : test_cases) {
             m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuid);
@@ -33042,8 +34932,7 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    std::array<const char *, 1> required_device_extensions = {
-        {VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME}};
+    std::array<const char *, 1> required_device_extensions = {{VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME}};
     for (auto device_extension : required_device_extensions) {
         if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
             m_device_extension_names.push_back(device_extension);
@@ -33067,7 +34956,6 @@
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
-
     // Test shading rate image creation
     VkImage image = VK_NULL_HANDLE;
     VkResult result = VK_RESULT_MAX_ENUM;
@@ -33127,7 +35015,6 @@
     result = vkCreateImage(m_device->device(), &image_create_info, NULL, &image);
     m_errorMonitor->VerifyNotFound();
 
-
     // bind memory to the image
     VkMemoryRequirements memory_reqs;
     VkDeviceMemory image_memory;
@@ -33146,7 +35033,6 @@
     result = vkBindImageMemory(m_device->device(), image, image_memory, 0);
     ASSERT_VK_SUCCESS(result);
 
-
     // Test image view creation
     VkImageView view;
     VkImageViewCreateInfo ivci = {};
@@ -33184,17 +35070,17 @@
 
     vkCreateImageView(m_device->device(), &ivci, nullptr, &view);
     m_errorMonitor->VerifyNotFound();
-    
 
     // Test pipeline creation
-    VkPipelineViewportShadingRateImageStateCreateInfoNV vsrisci = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV };
+    VkPipelineViewportShadingRateImageStateCreateInfoNV vsrisci = {
+        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV};
 
     VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
     VkViewport viewports[20] = {viewport, viewport};
     VkRect2D scissor = {{0, 0}, {64, 64}};
     VkRect2D scissors[20] = {scissor, scissor};
     VkDynamicState dynPalette = VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV;
-    VkPipelineDynamicStateCreateInfo dyn = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, 1, &dynPalette };
+    VkPipelineDynamicStateCreateInfo dyn = {VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, 1, &dynPalette};
 
     // viewportCount must be 0 or 1 when multiViewport is disabled
     {
@@ -33209,7 +35095,8 @@
             vsrisci.shadingRateImageEnable = VK_TRUE;
             vsrisci.viewportCount = 2;
         };
-        CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        CreatePipelineHelper::OneshotTest(
+            *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
             vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-viewportCount-02054",
                                  "VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216",
                                  "VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217"}));
@@ -33228,7 +35115,8 @@
             vsrisci.shadingRateImageEnable = VK_TRUE;
             vsrisci.viewportCount = 0;
         };
-        CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        CreatePipelineHelper::OneshotTest(
+            *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
             vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-shadingRateImageEnable-02056"}));
     }
 
@@ -33244,10 +35132,11 @@
             vsrisci.shadingRateImageEnable = VK_TRUE;
             vsrisci.viewportCount = 1;
         };
-        CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        CreatePipelineHelper::OneshotTest(
+            *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
             vector<std::string>({"VUID-VkPipelineViewportShadingRateImageStateCreateInfoNV-pDynamicStates-02057"}));
     }
-    
+
     // Create an image without the SRI bit
     VkImageObj nonSRIimage(m_device);
     nonSRIimage.Init(256, 256, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
@@ -33285,7 +35174,6 @@
                          nullptr, 0, nullptr, 1, &img_barrier);
     m_errorMonitor->VerifyNotFound();
 
-
     // Test vkCmdBindShadingRateImageNV errors
     auto vkCmdBindShadingRateImageNV =
         (PFN_vkCmdBindShadingRateImageNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdBindShadingRateImageNV");
@@ -33298,50 +35186,58 @@
     vkCmdBindShadingRateImageNV(m_commandBuffer->handle(), nonSRIview, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
     m_errorMonitor->VerifyFound();
 
-
     // Test vkCmdSetViewportShadingRatePaletteNV errors
     auto vkCmdSetViewportShadingRatePaletteNV =
         (PFN_vkCmdSetViewportShadingRatePaletteNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdSetViewportShadingRatePaletteNV");
 
     VkShadingRatePaletteEntryNV paletteEntries[100] = {};
-    VkShadingRatePaletteNV palette = { 100, paletteEntries };
-    VkShadingRatePaletteNV palettes[] = { palette, palette };
+    VkShadingRatePaletteNV palette = {100, paletteEntries};
+    VkShadingRatePaletteNV palettes[] = {palette, palette};
 
     // errors on firstViewport/viewportCount
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02066");
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02067");
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02068");
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetViewportShadingRatePaletteNV-viewportCount-02069");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02066");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02067");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02068");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkCmdSetViewportShadingRatePaletteNV-viewportCount-02069");
     vkCmdSetViewportShadingRatePaletteNV(m_commandBuffer->handle(), 20, 2, palettes);
     m_errorMonitor->VerifyFound();
 
     // shadingRatePaletteEntryCount must be in range
-    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkShadingRatePaletteNV-shadingRatePaletteEntryCount-02071");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-VkShadingRatePaletteNV-shadingRatePaletteEntryCount-02071");
     vkCmdSetViewportShadingRatePaletteNV(m_commandBuffer->handle(), 0, 1, palettes);
     m_errorMonitor->VerifyFound();
 
     VkCoarseSampleLocationNV locations[100] = {
-        {0, 0, 0},
-        {0, 0, 1},
-        {0, 1, 0},
-        {0, 1, 1},
-        {0, 1, 1}, // duplicate
-        {1000, 0, 0}, // pixelX too large
-        {0, 1000, 0}, // pixelY too large
-        {0, 0, 1000}, // sample too large
+        {0, 0, 0},    {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 1, 1},  // duplicate
+        {1000, 0, 0},                                              // pixelX too large
+        {0, 1000, 0},                                              // pixelY too large
+        {0, 0, 1000},                                              // sample too large
     };
 
     // Test custom sample orders, both via pipeline state and via dynamic state
     {
-        VkCoarseSampleOrderCustomNV sampOrdBadShadingRate = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV, 1, 1, locations };
-        VkCoarseSampleOrderCustomNV sampOrdBadSampleCount = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 3, 1, locations };
-        VkCoarseSampleOrderCustomNV sampOrdBadSampleLocationCount = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 2, locations };
-        VkCoarseSampleOrderCustomNV sampOrdDuplicateLocations = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 1*2*2, &locations[1] };
-        VkCoarseSampleOrderCustomNV sampOrdOutOfRangeLocations = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 1*2*2, &locations[4] };
-        VkCoarseSampleOrderCustomNV sampOrdTooLargeSampleLocationCount = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, 4, 64, &locations[8] };
-        VkCoarseSampleOrderCustomNV sampOrdGood = { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 1*2*2, &locations[0] };
+        VkCoarseSampleOrderCustomNV sampOrdBadShadingRate = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV, 1, 1,
+                                                             locations};
+        VkCoarseSampleOrderCustomNV sampOrdBadSampleCount = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 3, 1,
+                                                             locations};
+        VkCoarseSampleOrderCustomNV sampOrdBadSampleLocationCount = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV,
+                                                                     2, 2, locations};
+        VkCoarseSampleOrderCustomNV sampOrdDuplicateLocations = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2,
+                                                                 1 * 2 * 2, &locations[1]};
+        VkCoarseSampleOrderCustomNV sampOrdOutOfRangeLocations = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2,
+                                                                  1 * 2 * 2, &locations[4]};
+        VkCoarseSampleOrderCustomNV sampOrdTooLargeSampleLocationCount = {
+            VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, 4, 64, &locations[8]};
+        VkCoarseSampleOrderCustomNV sampOrdGood = {VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, 2, 1 * 2 * 2,
+                                                   &locations[0]};
 
-        VkPipelineViewportCoarseSampleOrderStateCreateInfoNV csosci = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV };
+        VkPipelineViewportCoarseSampleOrderStateCreateInfoNV csosci = {
+            VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV};
         csosci.sampleOrderType = VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV;
         csosci.customSampleOrderCount = 1;
 
@@ -33352,18 +35248,18 @@
         };
 
         vector<TestCase> test_cases = {
-            {&sampOrdBadShadingRate,        {"VUID-VkCoarseSampleOrderCustomNV-shadingRate-02073"}},
-            {&sampOrdBadSampleCount,        {"VUID-VkCoarseSampleOrderCustomNV-sampleCount-02074",
-                                             "VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}},
-            {&sampOrdBadSampleLocationCount,{"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}},
-            {&sampOrdDuplicateLocations,    {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}},
-            {&sampOrdOutOfRangeLocations,   {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077",
-                                             "VUID-VkCoarseSampleLocationNV-pixelX-02078",
-                                             "VUID-VkCoarseSampleLocationNV-pixelY-02079",
-                                             "VUID-VkCoarseSampleLocationNV-sample-02080"}},
-            {&sampOrdTooLargeSampleLocationCount, {"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02076",
-                                                   "VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}},
-            {&sampOrdGood,                  {}},
+            {&sampOrdBadShadingRate, {"VUID-VkCoarseSampleOrderCustomNV-shadingRate-02073"}},
+            {&sampOrdBadSampleCount,
+             {"VUID-VkCoarseSampleOrderCustomNV-sampleCount-02074", "VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}},
+            {&sampOrdBadSampleLocationCount, {"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02075"}},
+            {&sampOrdDuplicateLocations, {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}},
+            {&sampOrdOutOfRangeLocations,
+             {"VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077", "VUID-VkCoarseSampleLocationNV-pixelX-02078",
+              "VUID-VkCoarseSampleLocationNV-pixelY-02079", "VUID-VkCoarseSampleLocationNV-sample-02080"}},
+            {&sampOrdTooLargeSampleLocationCount,
+             {"VUID-VkCoarseSampleOrderCustomNV-sampleLocationCount-02076",
+              "VUID-VkCoarseSampleOrderCustomNV-pSampleLocations-02077"}},
+            {&sampOrdGood, {}},
         };
 
         for (const auto &test_case : test_cases) {
@@ -33390,14 +35286,14 @@
             }
         }
 
-        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetCoarseSampleOrderNV-sampleOrderType-02081");
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-vkCmdSetCoarseSampleOrderNV-sampleOrderType-02081");
         vkCmdSetCoarseSampleOrderNV(m_commandBuffer->handle(), VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV, 1, &sampOrdGood);
         m_errorMonitor->VerifyFound();
     }
 
     m_commandBuffer->end();
 
-
     vkDestroyImageView(m_device->device(), view, NULL);
     vkDestroyImage(m_device->device(), image, NULL);
     vkFreeMemory(m_device->device(), image_memory, NULL);
@@ -33414,8 +35310,7 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    std::array<const char *, 1> required_device_extensions = {
-        {VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME}};
+    std::array<const char *, 1> required_device_extensions = {{VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME}};
     for (auto device_extension : required_device_extensions) {
         if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
             m_device_extension_names.push_back(device_extension);
@@ -33542,7 +35437,6 @@
     }
 }
 
-
 TEST_F(VkLayerTest, MeshShaderNV) {
     TEST_DESCRIPTION("Test VK_NV_mesh_shader.");
 
@@ -33554,8 +35448,7 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    std::array<const char *, 1> required_device_extensions = {
-        {VK_NV_MESH_SHADER_EXTENSION_NAME}};
+    std::array<const char *, 1> required_device_extensions = {{VK_NV_MESH_SHADER_EXTENSION_NAME}};
     for (auto device_extension : required_device_extensions) {
         if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
             m_device_extension_names.push_back(device_extension);
@@ -33573,46 +35466,89 @@
     auto mesh_shader_features = lvl_init_struct<VkPhysicalDeviceMeshShaderFeaturesNV>();
     auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&mesh_shader_features);
     vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
+    features2.features.multiDrawIndirect = VK_FALSE;
 
     ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
     ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
 
-    VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this);
-    VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+    static const char vertShaderText[] =
+        "#version 450\n"
+        "vec2 vertices[3];\n"
+        "void main() {\n"
+        "      vertices[0] = vec2(-1.0, -1.0);\n"
+        "      vertices[1] = vec2( 1.0, -1.0);\n"
+        "      vertices[2] = vec2( 0.0,  1.0);\n"
+        "   gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
+        "   gl_PointSize = 1.0f;\n"
+        "}\n";
 
-    VkPipelineShaderStageCreateInfo meshStage = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
-    meshStage = vs.GetStageCreateInfo();
-    meshStage.stage = VK_SHADER_STAGE_MESH_BIT_NV;
+    static const char meshShaderText[] =
+        "#version 450\n"
+        "#extension GL_NV_mesh_shader : require\n"
+        "layout(local_size_x = 1) in;\n"
+        "layout(max_vertices = 3) out;\n"
+        "layout(max_primitives = 1) out;\n"
+        "layout(triangles) out;\n"
+        "void main() {\n"
+        "      gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0, 1);\n"
+        "      gl_MeshVerticesNV[1].gl_Position = vec4( 1.0, -1.0, 0, 1);\n"
+        "      gl_MeshVerticesNV[2].gl_Position = vec4( 0.0,  1.0, 0, 1);\n"
+        "      gl_PrimitiveIndicesNV[0] = 0;\n"
+        "      gl_PrimitiveIndicesNV[1] = 1;\n"
+        "      gl_PrimitiveIndicesNV[2] = 2;\n"
+        "      gl_PrimitiveCountNV = 1;\n"
+        "}\n";
+
+    VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj ms(m_device, meshShaderText, VK_SHADER_STAGE_MESH_BIT_NV, this);
+    VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this);
 
     // Test pipeline creation
     {
         // can't mix mesh with vertex
         const auto break_vp = [&](CreatePipelineHelper &helper) {
-            helper.shader_stages_ = { vs.GetStageCreateInfo(), fs.GetStageCreateInfo(), meshStage };
+            helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo(), ms.GetStageCreateInfo()};
         };
         CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-            vector<std::string>({"VUID-VkPipelineShaderStageCreateInfo-pName-00707",
-                                 "VUID-VkGraphicsPipelineCreateInfo-pStages-02095"}));
+                                          vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-pStages-02095"}));
 
         // vertex or mesh must be present
-        const auto break_vp2 = [&](CreatePipelineHelper &helper) {
-            helper.shader_stages_ = { fs.GetStageCreateInfo() };
-        };
+        const auto break_vp2 = [&](CreatePipelineHelper &helper) { helper.shader_stages_ = {fs.GetStageCreateInfo()}; };
         CreatePipelineHelper::OneshotTest(*this, break_vp2, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-            vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-stage-02096"}));
+                                          vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-stage-02096"}));
 
         // vertexinput and inputassembly must be valid when vertex stage is present
         const auto break_vp3 = [&](CreatePipelineHelper &helper) {
-            helper.shader_stages_ = { vs.GetStageCreateInfo(), fs.GetStageCreateInfo() };
+            helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
             helper.gp_ci_.pVertexInputState = nullptr;
             helper.gp_ci_.pInputAssemblyState = nullptr;
         };
         CreatePipelineHelper::OneshotTest(*this, break_vp3, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-            vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-pStages-02097",
-                                 "VUID-VkGraphicsPipelineCreateInfo-pStages-02098"}));
+                                          vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-pStages-02097",
+                                                               "VUID-VkGraphicsPipelineCreateInfo-pStages-02098"}));
     }
-}
 
+    PFN_vkCmdDrawMeshTasksIndirectNV vkCmdDrawMeshTasksIndirectNV =
+        (PFN_vkCmdDrawMeshTasksIndirectNV)vkGetInstanceProcAddr(instance(), "vkCmdDrawMeshTasksIndirectNV");
+
+    VkBufferCreateInfo buffer_create_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
+    buffer_create_info.size = sizeof(uint32_t);
+    buffer_create_info.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
+    VkBuffer buffer;
+    VkResult result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    ASSERT_VK_SUCCESS(result);
+
+    m_commandBuffer->begin();
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02146");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02147");
+    vkCmdDrawMeshTasksIndirectNV(m_commandBuffer->handle(), buffer, 0, 2, 0);
+    m_errorMonitor->VerifyFound();
+
+    m_commandBuffer->end();
+
+    vkDestroyBuffer(m_device->device(), buffer, 0);
+}
 
 TEST_F(VkLayerTest, MeshShaderDisabledNV) {
     TEST_DESCRIPTION("Test VK_NV_mesh_shader VUs with NV_mesh_shader disabled.");
@@ -33634,7 +35570,6 @@
     vkCmdSetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV);
     m_errorMonitor->VerifyFound();
 
-
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdResetEvent-stageMask-02109");
     vkCmdResetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV);
     m_errorMonitor->VerifyFound();
@@ -33643,26 +35578,28 @@
     vkCmdResetEvent(m_commandBuffer->handle(), event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV);
     m_errorMonitor->VerifyFound();
 
-
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdWaitEvents-srcStageMask-02111");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdWaitEvents-dstStageMask-02113");
-    vkCmdWaitEvents(m_commandBuffer->handle(), 1, &event, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr);
+    vkCmdWaitEvents(m_commandBuffer->handle(), 1, &event, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
+                    VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr);
     m_errorMonitor->VerifyFound();
 
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdWaitEvents-srcStageMask-02112");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdWaitEvents-dstStageMask-02114");
-    vkCmdWaitEvents(m_commandBuffer->handle(), 1, &event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr);
+    vkCmdWaitEvents(m_commandBuffer->handle(), 1, &event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
+                    VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr);
     m_errorMonitor->VerifyFound();
 
-
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-srcStageMask-02115");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-dstStageMask-02117");
-    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0, 0, nullptr, 0, nullptr, 0, nullptr);
+    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0,
+                         0, nullptr, 0, nullptr, 0, nullptr);
     m_errorMonitor->VerifyFound();
 
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-srcStageMask-02116");
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdPipelineBarrier-dstStageMask-02118");
-    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0, 0, nullptr, 0, nullptr, 0, nullptr);
+    vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0,
+                         0, nullptr, 0, nullptr, 0, nullptr);
     m_errorMonitor->VerifyFound();
 
     m_commandBuffer->end();
@@ -33696,22 +35633,21 @@
 
     vkQueueWaitIdle(m_device->m_queue);
 
-
     VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this);
-    VkPipelineShaderStageCreateInfo meshStage = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
+    VkPipelineShaderStageCreateInfo meshStage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
     meshStage = vs.GetStageCreateInfo();
     meshStage.stage = VK_SHADER_STAGE_MESH_BIT_NV;
-    VkPipelineShaderStageCreateInfo taskStage = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
+    VkPipelineShaderStageCreateInfo taskStage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
     taskStage = vs.GetStageCreateInfo();
     taskStage.stage = VK_SHADER_STAGE_TASK_BIT_NV;
 
     // mesh and task shaders not supported
     const auto break_vp = [&](CreatePipelineHelper &helper) {
-        helper.shader_stages_ = { meshStage, taskStage, vs.GetStageCreateInfo() };
+        helper.shader_stages_ = {meshStage, taskStage, vs.GetStageCreateInfo()};
     };
-    CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        vector<std::string>({"VUID-VkPipelineShaderStageCreateInfo-pName-00707",
-                             "VUID-VkPipelineShaderStageCreateInfo-pName-00707",
+    CreatePipelineHelper::OneshotTest(
+        *this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        vector<std::string>({"VUID-VkPipelineShaderStageCreateInfo-pName-00707", "VUID-VkPipelineShaderStageCreateInfo-pName-00707",
                              "VUID-VkPipelineShaderStageCreateInfo-stage-02091",
                              "VUID-VkPipelineShaderStageCreateInfo-stage-02092"}));
 
@@ -33719,7 +35655,6 @@
     vkDestroySemaphore(m_device->device(), semaphore, nullptr);
 }
 
-
 TEST_F(VkLayerTest, InlineUniformBlockEXT) {
     TEST_DESCRIPTION("Test VK_EXT_inline_uniform_block.");
 
@@ -33731,8 +35666,8 @@
         return;
     }
     ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
-    std::array<const char *, 1> required_device_extensions = {
-        {VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME}};
+    std::array<const char *, 2> required_device_extensions = {VK_KHR_MAINTENANCE1_EXTENSION_NAME,
+                                                              VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME};
     for (auto device_extension : required_device_extensions) {
         if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
             m_device_extension_names.push_back(device_extension);
@@ -33743,9 +35678,16 @@
     }
 
     // Enable descriptor indexing if supported, but don't require it.
-    bool supportsDescriptorIndexing = DeviceExtensionSupported(gpu(), nullptr, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
-    if (supportsDescriptorIndexing) {
-        m_device_extension_names.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
+    bool supportsDescriptorIndexing = true;
+    required_device_extensions = {VK_KHR_MAINTENANCE3_EXTENSION_NAME, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME};
+    for (auto device_extension : required_device_extensions) {
+        if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
+            m_device_extension_names.push_back(device_extension);
+        } else {
+            printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension);
+            supportsDescriptorIndexing = false;
+            return;
+        }
     }
 
     PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR =
@@ -33898,20 +35840,20 @@
 
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-02220");
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     descriptor_write.dstArrayElement = 1;
     descriptor_write.descriptorCount = 4;
     write_inline_uniform.dataSize = 4;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-02219");
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     descriptor_write.pNext = nullptr;
     descriptor_write.dstArrayElement = 0;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkWriteDescriptorSet-descriptorType-02221");
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     descriptor_write.pNext = &write_inline_uniform;
     vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
@@ -33921,38 +35863,1785 @@
     VkCopyDescriptorSet copy_ds_update = {};
     copy_ds_update.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET;
     copy_ds_update.srcSet = descriptor_sets[0];
-    copy_ds_update.srcBinding = 0; 
+    copy_ds_update.srcBinding = 0;
     copy_ds_update.srcArrayElement = 0;
     copy_ds_update.dstSet = descriptor_sets[1];
     copy_ds_update.dstBinding = 0;
-    copy_ds_update.dstArrayElement = 0; 
+    copy_ds_update.dstArrayElement = 0;
     copy_ds_update.descriptorCount = 4;
-    
+
     copy_ds_update.srcArrayElement = 1;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkCopyDescriptorSet-srcBinding-02223");
     vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, &copy_ds_update);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     copy_ds_update.srcArrayElement = 0;
     copy_ds_update.dstArrayElement = 1;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkCopyDescriptorSet-dstBinding-02224");
     vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, &copy_ds_update);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     copy_ds_update.dstArrayElement = 0;
     copy_ds_update.descriptorCount = 5;
     m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkCopyDescriptorSet-srcBinding-02225");
     vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, &copy_ds_update);
-    m_errorMonitor->VerifyFound();    
+    m_errorMonitor->VerifyFound();
 
     copy_ds_update.descriptorCount = 4;
     vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, &copy_ds_update);
-    m_errorMonitor->VerifyNotFound();    
+    m_errorMonitor->VerifyNotFound();
 
     vkDestroyDescriptorPool(m_device->handle(), ds_pool, nullptr);
     vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, nullptr);
 }
 
+TEST_F(VkLayerTest, FramebufferMixedSamplesNV) {
+    TEST_DESCRIPTION("Verify VK_NV_framebuffer_mixed_samples.");
+
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    struct TestCase {
+        VkSampleCountFlagBits color_samples;
+        VkSampleCountFlagBits depth_samples;
+        VkSampleCountFlagBits raster_samples;
+        VkBool32 depth_test;
+        VkBool32 sample_shading;
+        uint32_t table_count;
+        bool positiveTest;
+        std::string vuid;
+    };
+
+    std::vector<TestCase> test_cases = {
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-00757"},
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 4, false,
+         "VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405"},
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 2, true,
+         "VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405"},
+        {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_TRUE, VK_FALSE, 1, false,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-01411"},
+        {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_8_BIT, VK_TRUE, VK_FALSE, 1, true,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-01411"},
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT, VK_FALSE, VK_FALSE, 1, false,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-01412"},
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-01412"},
+        {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_TRUE, 1, false,
+         "VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415"},
+        {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
+         "VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415"},
+        {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 1, true,
+         "VUID-VkGraphicsPipelineCreateInfo-subpass-00757"}};
+
+    for (const auto &test_case : test_cases) {
+        VkAttachmentDescription att[2] = {{}, {}};
+        att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
+        att[0].samples = test_case.color_samples;
+        att[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        att[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
+        att[1].samples = test_case.depth_samples;
+        att[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+        VkAttachmentReference cr = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+        VkAttachmentReference dr = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
+
+        VkSubpassDescription sp = {};
+        sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+        sp.colorAttachmentCount = 1;
+        sp.pColorAttachments = &cr;
+        sp.pResolveAttachments = NULL;
+        sp.pDepthStencilAttachment = &dr;
+
+        VkRenderPassCreateInfo rpi = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
+        rpi.attachmentCount = 2;
+        rpi.pAttachments = att;
+        rpi.subpassCount = 1;
+        rpi.pSubpasses = &sp;
+
+        VkRenderPass rp;
+
+        m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                             "VUID-VkSubpassDescription-pDepthStencilAttachment-01418");
+        VkResult err = vkCreateRenderPass(m_device->device(), &rpi, nullptr, &rp);
+        m_errorMonitor->VerifyNotFound();
+
+        ASSERT_VK_SUCCESS(err);
+
+        VkPipelineDepthStencilStateCreateInfo ds = {VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
+        VkPipelineCoverageModulationStateCreateInfoNV cmi = {VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV};
+
+        // Create a dummy modulation table that can be used for the positive
+        // coverageModulationTableCount test.
+        std::vector<float> cm_table{};
+
+        const auto break_samples = [&cmi, &rp, &ds, &cm_table, &test_case](CreatePipelineHelper &helper) {
+            cm_table.resize(test_case.raster_samples / test_case.color_samples);
+
+            cmi.flags = 0;
+            cmi.coverageModulationTableEnable = (test_case.table_count > 1);
+            cmi.coverageModulationTableCount = test_case.table_count;
+            cmi.pCoverageModulationTable = cm_table.data();
+
+            ds.depthTestEnable = test_case.depth_test;
+
+            helper.pipe_ms_state_ci_.pNext = &cmi;
+            helper.pipe_ms_state_ci_.rasterizationSamples = test_case.raster_samples;
+            helper.pipe_ms_state_ci_.sampleShadingEnable = test_case.sample_shading;
+
+            helper.gp_ci_.renderPass = rp;
+            helper.gp_ci_.pDepthStencilState = &ds;
+        };
+
+        CreatePipelineHelper::OneshotTest(*this, break_samples, VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuid,
+                                          test_case.positiveTest);
+
+        vkDestroyRenderPass(m_device->device(), rp, nullptr);
+    }
+}
+
+TEST_F(VkLayerTest, FramebufferMixedSamples) {
+    TEST_DESCRIPTION("Verify that the expected VUIds are hits when VK_NV_framebuffer_mixed_samples is disabled.");
+
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    struct TestCase {
+        VkSampleCountFlagBits color_samples;
+        VkSampleCountFlagBits depth_samples;
+        VkSampleCountFlagBits raster_samples;
+        bool positiveTest;
+    };
+
+    std::vector<TestCase> test_cases = {
+        {VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT,
+         false},  // Fails vkCreateRenderPass and vkCreateGraphicsPipeline
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, false},  // Fails vkCreateGraphicsPipeline
+        {VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, true}    // Pass
+    };
+
+    for (const auto &test_case : test_cases) {
+        VkAttachmentDescription att[2] = {{}, {}};
+        att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
+        att[0].samples = test_case.color_samples;
+        att[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        att[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
+        att[1].samples = test_case.depth_samples;
+        att[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+        VkAttachmentReference cr = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+        VkAttachmentReference dr = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
+
+        VkSubpassDescription sp = {};
+        sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+        sp.colorAttachmentCount = 1;
+        sp.pColorAttachments = &cr;
+        sp.pResolveAttachments = NULL;
+        sp.pDepthStencilAttachment = &dr;
+
+        VkRenderPassCreateInfo rpi = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
+        rpi.attachmentCount = 2;
+        rpi.pAttachments = att;
+        rpi.subpassCount = 1;
+        rpi.pSubpasses = &sp;
+
+        VkRenderPass rp;
+
+        if (test_case.color_samples == test_case.depth_samples) {
+            m_errorMonitor->ExpectSuccess();
+        } else {
+            m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                                 "VUID-VkSubpassDescription-pDepthStencilAttachment-01418");
+        }
+
+        VkResult err = vkCreateRenderPass(m_device->device(), &rpi, nullptr, &rp);
+
+        if (test_case.color_samples == test_case.depth_samples) {
+            m_errorMonitor->VerifyNotFound();
+        } else {
+            m_errorMonitor->VerifyFound();
+            continue;
+        }
+
+        ASSERT_VK_SUCCESS(err);
+
+        VkPipelineDepthStencilStateCreateInfo ds = {VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
+
+        const auto break_samples = [&rp, &ds, &test_case](CreatePipelineHelper &helper) {
+            helper.pipe_ms_state_ci_.rasterizationSamples = test_case.raster_samples;
+
+            helper.gp_ci_.renderPass = rp;
+            helper.gp_ci_.pDepthStencilState = &ds;
+        };
+
+        CreatePipelineHelper::OneshotTest(*this, break_samples, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                          "VUID-VkGraphicsPipelineCreateInfo-subpass-00757", test_case.positiveTest);
+
+        vkDestroyRenderPass(m_device->device(), rp, nullptr);
+    }
+}
+
+TEST_F(VkLayerTest, FragmentCoverageToColorNV) {
+    TEST_DESCRIPTION("Verify VK_NV_fragment_coverage_to_color.");
+
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    struct TestCase {
+        VkFormat format;
+        VkBool32 enabled;
+        uint32_t location;
+        bool positive;
+    };
+
+    const std::array<TestCase, 9> test_cases = {{
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_FALSE, 0, true},
+        {VK_FORMAT_R8_UINT, VK_TRUE, 1, true},
+        {VK_FORMAT_R16_UINT, VK_TRUE, 1, true},
+        {VK_FORMAT_R16_SINT, VK_TRUE, 1, true},
+        {VK_FORMAT_R32_UINT, VK_TRUE, 1, true},
+        {VK_FORMAT_R32_SINT, VK_TRUE, 1, true},
+        {VK_FORMAT_R32_SINT, VK_TRUE, 2, false},
+        {VK_FORMAT_R8_SINT, VK_TRUE, 3, false},
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_TRUE, 1, false},
+    }};
+
+    for (const auto &test_case : test_cases) {
+        std::array<VkAttachmentDescription, 2> att = {{{}, {}}};
+        att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
+        att[0].samples = VK_SAMPLE_COUNT_1_BIT;
+        att[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        att[1].format = VK_FORMAT_R8G8B8A8_UNORM;
+        att[1].samples = VK_SAMPLE_COUNT_1_BIT;
+        att[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        att[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+        if (test_case.location < att.size()) {
+            att[test_case.location].format = test_case.format;
+        }
+
+        const std::array<VkAttachmentReference, 3> cr = {{{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+                                                          {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
+                                                          {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}};
+
+        VkSubpassDescription sp = {};
+        sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+        sp.colorAttachmentCount = cr.size();
+        sp.pColorAttachments = cr.data();
+
+        VkRenderPassCreateInfo rpi = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
+        rpi.attachmentCount = att.size();
+        rpi.pAttachments = att.data();
+        rpi.subpassCount = 1;
+        rpi.pSubpasses = &sp;
+
+        const std::array<VkPipelineColorBlendAttachmentState, 3> cba = {{{}, {}, {}}};
+
+        VkPipelineColorBlendStateCreateInfo cbi = {VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
+        cbi.attachmentCount = cba.size();
+        cbi.pAttachments = cba.data();
+
+        VkRenderPass rp;
+        VkResult err = vkCreateRenderPass(m_device->device(), &rpi, nullptr, &rp);
+        ASSERT_VK_SUCCESS(err);
+
+        VkPipelineCoverageToColorStateCreateInfoNV cci = {VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV};
+
+        const auto break_samples = [&cci, &cbi, &rp, &test_case](CreatePipelineHelper &helper) {
+            cci.coverageToColorEnable = test_case.enabled;
+            cci.coverageToColorLocation = test_case.location;
+
+            helper.pipe_ms_state_ci_.pNext = &cci;
+            helper.gp_ci_.renderPass = rp;
+            helper.gp_ci_.pColorBlendState = &cbi;
+        };
+
+        CreatePipelineHelper::OneshotTest(*this, break_samples, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                          "VUID-VkPipelineCoverageToColorStateCreateInfoNV-coverageToColorEnable-01404",
+                                          test_case.positive);
+
+        vkDestroyRenderPass(m_device->device(), rp, nullptr);
+    }
+}
+
+TEST_F(VkPositiveLayerTest, RayTracingPipelineNV) {
+    TEST_DESCRIPTION("Test VK_NV_ray_tracing.");
+
+    if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    } else {
+        printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix,
+               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    std::array<const char *, 2> required_device_extensions = {
+        {VK_NV_RAY_TRACING_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME}};
+    for (auto device_extension : required_device_extensions) {
+        if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
+            m_device_extension_names.push_back(device_extension);
+        } else {
+            printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension);
+            return;
+        }
+    }
+
+    PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR =
+        (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR");
+    ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+
+    m_errorMonitor->ExpectSuccess();
+
+    static const char rayGenShaderText[] =
+        "#version 460 core                                                \n"
+        "#extension GL_NV_ray_tracing : require                           \n"
+        "layout(set = 0, binding = 0, rgba8) uniform image2D image;       \n"
+        "layout(set = 0, binding = 1) uniform accelerationStructureNV as; \n"
+        "                                                                 \n"
+        "layout(location = 0) rayPayloadNV float payload;                 \n"
+        "                                                                 \n"
+        "void main()                                                      \n"
+        "{                                                                \n"
+        "   vec4 col = vec4(0, 0, 0, 1);                                  \n"
+        "                                                                 \n"
+        "   vec3 origin = vec3(float(gl_LaunchIDNV.x)/float(gl_LaunchSizeNV.x), float(gl_LaunchIDNV.y)/float(gl_LaunchSizeNV.y), "
+        "1.0); \n"
+        "   vec3 dir = vec3(0.0, 0.0, -1.0);                              \n"
+        "                                                                 \n"
+        "   payload = 0.5;                                                \n"
+        "   traceNV(as, gl_RayFlagsCullBackFacingTrianglesNV, 0xff, 0, 1, 0, origin, 0.0, dir, 1000.0, 0); \n"
+        "                                                                 \n"
+        "   col.y = payload;                                              \n"
+        "                                                                 \n"
+        "   imageStore(image, ivec2(gl_LaunchIDNV.xy), col);              \n"
+        "}\n";
+
+    static char const closestHitShaderText[] =
+        "#version 460 core                              \n"
+        "#extension GL_NV_ray_tracing : require         \n"
+        "layout(location = 0) rayPayloadInNV float hitValue;             \n"
+        "                                               \n"
+        "void main() {                                  \n"
+        "    hitValue = 1.0;                            \n"
+        "}                                              \n";
+
+    static char const missShaderText[] =
+        "#version 460 core                              \n"
+        "#extension GL_NV_ray_tracing : require         \n"
+        "layout(location = 0) rayPayloadInNV float hitValue; \n"
+        "                                               \n"
+        "void main() {                                  \n"
+        "    hitValue = 0.0;                            \n"
+        "}                                              \n";
+
+    VkShaderObj rgs(m_device, rayGenShaderText, VK_SHADER_STAGE_RAYGEN_BIT_NV, this);
+    VkShaderObj chs(m_device, closestHitShaderText, VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV, this);
+    VkShaderObj mis(m_device, missShaderText, VK_SHADER_STAGE_MISS_BIT_NV, this);
+
+    VkPipelineShaderStageCreateInfo rayStages[3];
+    memset(&rayStages[0], 0, sizeof(rayStages));
+
+    rayStages[0] = rgs.GetStageCreateInfo();
+    rayStages[0].stage = VK_SHADER_STAGE_RAYGEN_BIT_NV;
+    rayStages[1] = chs.GetStageCreateInfo();
+    rayStages[1].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
+    rayStages[2] = mis.GetStageCreateInfo();
+    rayStages[2].stage = VK_SHADER_STAGE_MISS_BIT_NV;
+
+    VkRayTracingShaderGroupCreateInfoNV groups[3];
+    memset(&groups[0], 0, sizeof(groups));
+
+    groups[0].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
+    groups[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
+    groups[0].generalShader = 0;
+    groups[0].closestHitShader = VK_SHADER_UNUSED_NV;
+    groups[0].anyHitShader = VK_SHADER_UNUSED_NV;
+    groups[0].intersectionShader = VK_SHADER_UNUSED_NV;
+
+    groups[1].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
+    groups[1].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
+    groups[1].generalShader = VK_SHADER_UNUSED_NV;
+    groups[1].closestHitShader = 1;
+    groups[1].anyHitShader = VK_SHADER_UNUSED_NV;
+    groups[1].intersectionShader = VK_SHADER_UNUSED_NV;
+
+    groups[2].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
+    groups[2].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
+    groups[2].generalShader = 2;
+    groups[2].closestHitShader = VK_SHADER_UNUSED_NV;
+    groups[2].anyHitShader = VK_SHADER_UNUSED_NV;
+    groups[2].intersectionShader = VK_SHADER_UNUSED_NV;
+
+    const uint32_t bindingCount = 2;
+    VkDescriptorSetLayoutBinding binding[bindingCount] = {};
+    binding[0].binding = 0;
+    binding[0].descriptorCount = 1;
+    binding[0].stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
+    binding[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+    binding[1].binding = 1;
+    binding[1].descriptorCount = 1;
+    binding[1].stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
+    binding[1].descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
+
+    VkDescriptorSetLayoutCreateInfo descriptorSetEntry = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
+    descriptorSetEntry.bindingCount = bindingCount;
+    descriptorSetEntry.pBindings = binding;
+
+    VkDescriptorSetLayout descriptorSetLayout;
+    VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &descriptorSetEntry, 0, &descriptorSetLayout);
+    ASSERT_VK_SUCCESS(err);
+    VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
+    pipelineLayoutCreateInfo.setLayoutCount = 1;
+    pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
+    VkPipelineLayout pipelineLayout;
+    err = vkCreatePipelineLayout(m_device->device(), &pipelineLayoutCreateInfo, 0, &pipelineLayout);
+    ASSERT_VK_SUCCESS(err);
+
+    PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV =
+        (PFN_vkCreateRayTracingPipelinesNV)vkGetInstanceProcAddr(instance(), "vkCreateRayTracingPipelinesNV");
+
+    VkRayTracingPipelineCreateInfoNV rayPipelineInfo = {VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV};
+    rayPipelineInfo.layout = pipelineLayout;
+
+    rayPipelineInfo.stageCount = 3;
+    rayPipelineInfo.pStages = &rayStages[0];
+    rayPipelineInfo.groupCount = 3;
+    rayPipelineInfo.pGroups = &groups[0];
+
+    VkPipeline rayPipeline;
+    err = vkCreateRayTracingPipelinesNV(m_device->device(), VK_NULL_HANDLE, 1, &rayPipelineInfo, 0, &rayPipeline);
+    ASSERT_VK_SUCCESS(err);
+
+    vkDestroyPipeline(m_device->device(), rayPipeline, 0);
+    vkDestroyPipelineLayout(m_device->device(), pipelineLayout, 0);
+    vkDestroyDescriptorSetLayout(m_device->device(), descriptorSetLayout, 0);
+    m_errorMonitor->VerifyNotFound();
+}
+
+TEST_F(VkLayerTest, CreateYCbCrSampler) {
+    TEST_DESCRIPTION("Verify YCbCr sampler creation.");
+
+    // Test requires API 1.1 or (API 1.0 + SamplerYCbCr extension). Request API 1.1
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    // In case we don't have API 1.1+, try enabling the extension directly (and it's dependencies)
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    // Verify we have the requested support
+    bool ycbcr_support = (DeviceExtensionEnabled(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME) ||
+                          (DeviceValidationVersion() >= VK_API_VERSION_1_1));
+    if (!ycbcr_support) {
+        printf("%s Did not find required device extension %s; test skipped.\n", kSkipPrefix,
+               VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        return;
+    }
+
+    VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE;
+    VkSamplerYcbcrConversionCreateInfo sycci = {};
+    sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
+    sycci.format = VK_FORMAT_UNDEFINED;
+    sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+    sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01649");
+    vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv);
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkPositiveLayerTest, ViewportArray2NV) {
+    TEST_DESCRIPTION("Test to validate VK_NV_viewport_array2");
+
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    VkPhysicalDeviceFeatures available_features = {};
+    ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&available_features));
+
+    if (!available_features.multiViewport) {
+        printf("VkPhysicalDeviceFeatures::multiViewport is not supported, skipping tests\n");
+        return;
+    }
+    if (!available_features.tessellationShader) {
+        printf("VkPhysicalDeviceFeatures::tessellationShader is not supported, skipping tests\n");
+        return;
+    }
+    if (!available_features.geometryShader) {
+        printf("VkPhysicalDeviceFeatures::geometryShader is not supported, skipping tests\n");
+        return;
+    }
+
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    const char tcs_src[] = R"(
+        #version 450
+        layout(vertices = 3) out;
+
+        void main() {
+            gl_TessLevelOuter[0] = 4.0f;
+            gl_TessLevelOuter[1] = 4.0f;
+            gl_TessLevelOuter[2] = 4.0f;
+            gl_TessLevelInner[0] = 3.0f;
+
+            gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
+        })";
+
+    const char fs_src[] = R"(
+        #version 450
+        layout(location = 0) out vec4 outColor;
+        void main() {
+            outColor = vec4(1.0f);
+        })";
+
+    // Create tessellation control and fragment shader here since they will not be
+    // modified by the different test cases.
+    VkShaderObj tcs(m_device, tcs_src, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this);
+    VkShaderObj fs(m_device, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    std::vector<VkViewport> vps = {{0.0f, 0.0f, m_width / 2.0f, m_height}, {m_width / 2.0f, 0.0f, m_width / 2.0f, m_height}};
+    std::vector<VkRect2D> scs = {
+        {{0, 0}, {static_cast<uint32_t>(m_width) / 2, static_cast<uint32_t>(m_height)}},
+        {{static_cast<int32_t>(m_width) / 2, 0}, {static_cast<uint32_t>(m_width) / 2, static_cast<uint32_t>(m_height)}}};
+
+    enum class TestStage { VERTEX = 0, TESSELLATION_EVAL = 1, GEOMETRY = 2 };
+    std::array<TestStage, 3> vertex_stages = {{TestStage::VERTEX, TestStage::TESSELLATION_EVAL, TestStage::GEOMETRY}};
+
+    // Verify that the usage of gl_ViewportMask[] in the allowed vertex processing
+    // stages does not cause any errors.
+    for (auto stage : vertex_stages) {
+        m_errorMonitor->ExpectSuccess();
+
+        VkPipelineInputAssemblyStateCreateInfo iaci = {VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
+        iaci.topology = (stage != TestStage::VERTEX) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+        VkPipelineTessellationStateCreateInfo tsci = {VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO};
+        tsci.patchControlPoints = 3;
+
+        const VkPipelineLayoutObj pl(m_device);
+
+        VkPipelineObj pipe(m_device);
+        pipe.AddDefaultColorAttachment();
+        pipe.SetInputAssembly(&iaci);
+        pipe.SetViewport(vps);
+        pipe.SetScissor(scs);
+        pipe.AddShader(&fs);
+
+        std::stringstream vs_src, tes_src, geom_src;
+
+        vs_src << R"(
+            #version 450
+            #extension GL_NV_viewport_array2 : require
+
+            vec2 positions[3] = { vec2( 0.0f, -0.5f),
+                                  vec2( 0.5f,  0.5f),
+                                  vec2(-0.5f,  0.5f)
+                                };
+            void main() {)";
+        // Write viewportMask if the vertex shader is the last vertex processing stage.
+        if (stage == TestStage::VERTEX) {
+            vs_src << "gl_ViewportMask[0] = 3;\n";
+        }
+        vs_src << R"(
+                gl_Position = vec4(positions[gl_VertexIndex % 3], 0.0, 1.0);
+            })";
+
+        VkShaderObj vs(m_device, vs_src.str().c_str(), VK_SHADER_STAGE_VERTEX_BIT, this);
+        pipe.AddShader(&vs);
+
+        std::unique_ptr<VkShaderObj> tes, geom;
+
+        if (stage >= TestStage::TESSELLATION_EVAL) {
+            tes_src << R"(
+                #version 450
+                #extension GL_NV_viewport_array2 : require
+                layout(triangles) in;
+
+                void main() {
+                   gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x +
+                                  gl_in[1].gl_Position * gl_TessCoord.y +
+                                  gl_in[2].gl_Position * gl_TessCoord.z);)";
+            // Write viewportMask if the tess eval shader is the last vertex processing stage.
+            if (stage == TestStage::TESSELLATION_EVAL) {
+                tes_src << "gl_ViewportMask[0] = 3;\n";
+            }
+            tes_src << "}";
+
+            tes = std::unique_ptr<VkShaderObj>(
+                new VkShaderObj(m_device, tes_src.str().c_str(), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this));
+            pipe.AddShader(tes.get());
+            pipe.AddShader(&tcs);
+            pipe.SetTessellation(&tsci);
+        }
+
+        if (stage >= TestStage::GEOMETRY) {
+            geom_src << R"(
+                #version 450
+                #extension GL_NV_viewport_array2 : require
+                layout(triangles)   in;
+                layout(triangle_strip, max_vertices = 3) out;
+
+                void main() {
+                   gl_ViewportMask[0] = 3;
+                   for(int i = 0; i < 3; ++i) {
+                       gl_Position = gl_in[i].gl_Position;
+                       EmitVertex();
+                    }
+                })";
+
+            geom =
+                std::unique_ptr<VkShaderObj>(new VkShaderObj(m_device, geom_src.str().c_str(), VK_SHADER_STAGE_GEOMETRY_BIT, this));
+            pipe.AddShader(geom.get());
+        }
+
+        pipe.CreateVKPipeline(pl.handle(), renderPass());
+        m_errorMonitor->VerifyNotFound();
+    }
+}
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+#include "android_ndk_types.h"
+
+TEST_F(VkLayerTest, AndroidHardwareBufferImageCreate) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer image create info.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkImage img = VK_NULL_HANDLE;
+    auto reset_img = [&img, dev]() {
+        if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL);
+        img = VK_NULL_HANDLE;
+    };
+
+    VkImageCreateInfo ici = {};
+    ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    ici.pNext = nullptr;
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.arrayLayers = 1;
+    ici.extent = {64, 64, 1};
+    ici.format = VK_FORMAT_UNDEFINED;
+    ici.mipLevels = 1;
+    ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    ici.samples = VK_SAMPLE_COUNT_1_BIT;
+    ici.tiling = VK_IMAGE_TILING_OPTIMAL;
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+    // undefined format
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01975");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+
+    // also undefined format
+    VkExternalFormatANDROID efa = {};
+    efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
+    efa.externalFormat = 0;
+    ici.pNext = &efa;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01975");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+
+    // undefined format with an unknown external format
+    efa.externalFormat = 0xBADC0DE;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkExternalFormatANDROID-externalFormat-01894");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+
+    AHardwareBuffer *ahb;
+    AHardwareBuffer_Desc ahb_desc = {};
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ahb_desc.width = 64;
+    ahb_desc.height = 64;
+    ahb_desc.layers = 1;
+    // Allocate an AHardwareBuffer
+    AHardwareBuffer_allocate(&ahb_desc, &ahb);
+
+    // Retrieve it's properties to make it's external format 'known' (AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM)
+    VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {};
+    ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
+    VkAndroidHardwareBufferPropertiesANDROID ahb_props = {};
+    ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
+    ahb_props.pNext = &ahb_fmt_props;
+    PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps =
+        (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID");
+    ASSERT_TRUE(pfn_GetAHBProps != nullptr);
+    pfn_GetAHBProps(dev, ahb, &ahb_props);
+
+    // a defined image format with a non-zero external format
+    ici.format = VK_FORMAT_R8G8B8A8_UNORM;
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-01974");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+    ici.format = VK_FORMAT_UNDEFINED;
+
+    // external format while MUTABLE
+    ici.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02396");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+    ici.flags = 0;
+
+    // external format while usage other than SAMPLED
+    ici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02397");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+    // external format while tiline other than OPTIMAL
+    ici.tiling = VK_IMAGE_TILING_LINEAR;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02398");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+    ici.tiling = VK_IMAGE_TILING_OPTIMAL;
+
+    // imageType
+    VkExternalMemoryImageCreateInfo emici = {};
+    emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+    emici.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+    ici.pNext = &emici;  // remove efa from chain, insert emici
+    ici.format = VK_FORMAT_R8G8B8A8_UNORM;
+    ici.imageType = VK_IMAGE_TYPE_3D;
+    ici.extent = {64, 64, 64};
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02393");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+
+    // wrong mipLevels
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.extent = {64, 64, 1};
+    ici.mipLevels = 6;  // should be 7
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageCreateInfo-pNext-02394");
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyFound();
+    reset_img();
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferFetchUnboundImageInfo) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer retreive image properties while memory unbound.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkImage img = VK_NULL_HANDLE;
+    auto reset_img = [&img, dev]() {
+        if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL);
+        img = VK_NULL_HANDLE;
+    };
+
+    VkImageCreateInfo ici = {};
+    ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    ici.pNext = nullptr;
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.arrayLayers = 1;
+    ici.extent = {64, 64, 1};
+    ici.format = VK_FORMAT_R8G8B8A8_UNORM;
+    ici.mipLevels = 1;
+    ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    ici.samples = VK_SAMPLE_COUNT_1_BIT;
+    ici.tiling = VK_IMAGE_TILING_LINEAR;
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+    VkExternalMemoryImageCreateInfo emici = {};
+    emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+    emici.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+    ici.pNext = &emici;
+
+    m_errorMonitor->ExpectSuccess();
+    vkCreateImage(dev, &ici, NULL, &img);
+    m_errorMonitor->VerifyNotFound();
+
+    // attempt to fetch layout from unbound image
+    VkImageSubresource sub_rsrc = {};
+    sub_rsrc.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    VkSubresourceLayout sub_layout = {};
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetImageSubresourceLayout-image-01895");
+    vkGetImageSubresourceLayout(dev, img, &sub_rsrc, &sub_layout);
+    m_errorMonitor->VerifyFound();
+
+    // attempt to get memory reqs from unbound image
+    VkImageMemoryRequirementsInfo2 imri = {};
+    imri.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
+    imri.image = img;
+    VkMemoryRequirements2 mem_reqs = {};
+    mem_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageMemoryRequirementsInfo2-image-01897");
+    vkGetImageMemoryRequirements2(dev, &imri, &mem_reqs);
+    m_errorMonitor->VerifyFound();
+
+    reset_img();
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferMemoryAllocation) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer memory allocation.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkImage img = VK_NULL_HANDLE;
+    auto reset_img = [&img, dev]() {
+        if (VK_NULL_HANDLE != img) vkDestroyImage(dev, img, NULL);
+        img = VK_NULL_HANDLE;
+    };
+    VkDeviceMemory mem_handle = VK_NULL_HANDLE;
+    auto reset_mem = [&mem_handle, dev]() {
+        if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL);
+        mem_handle = VK_NULL_HANDLE;
+    };
+
+    PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps =
+        (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID");
+    ASSERT_TRUE(pfn_GetAHBProps != nullptr);
+
+    // AHB structs
+    AHardwareBuffer *ahb = nullptr;
+    AHardwareBuffer_Desc ahb_desc = {};
+    VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {};
+    ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
+    VkAndroidHardwareBufferPropertiesANDROID ahb_props = {};
+    ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
+    ahb_props.pNext = &ahb_fmt_props;
+    VkImportAndroidHardwareBufferInfoANDROID iahbi = {};
+    iahbi.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
+
+    // destroy and re-acquire an AHB, and fetch it's properties
+    auto recreate_ahb = [&ahb, &iahbi, &ahb_desc, &ahb_props, dev, pfn_GetAHBProps]() {
+        if (ahb) AHardwareBuffer_release(ahb);
+        ahb = nullptr;
+        AHardwareBuffer_allocate(&ahb_desc, &ahb);
+        pfn_GetAHBProps(dev, ahb, &ahb_props);
+        iahbi.buffer = ahb;
+    };
+
+    // Allocate an AHardwareBuffer
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ahb_desc.width = 64;
+    ahb_desc.height = 64;
+    ahb_desc.layers = 1;
+    recreate_ahb();
+
+    // Create an image w/ external format
+    VkExternalFormatANDROID efa = {};
+    efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+
+    VkImageCreateInfo ici = {};
+    ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    ici.pNext = &efa;
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.arrayLayers = 1;
+    ici.extent = {64, 64, 1};
+    ici.format = VK_FORMAT_UNDEFINED;
+    ici.mipLevels = 1;
+    ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    ici.mipLevels = 1;
+    ici.samples = VK_SAMPLE_COUNT_1_BIT;
+    ici.tiling = VK_IMAGE_TILING_OPTIMAL;
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+    VkResult res = vkCreateImage(dev, &ici, NULL, &img);
+    ASSERT_VK_SUCCESS(res);
+
+    VkMemoryAllocateInfo mai = {};
+    mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mai.pNext = &iahbi;  // Chained import struct
+    mai.allocationSize = ahb_props.allocationSize;
+    mai.memoryTypeIndex = 32;
+    // Set index to match one of the bits in ahb_props
+    for (int i = 0; i < 32; i++) {
+        if (ahb_props.memoryTypeBits & (1 << i)) {
+            mai.memoryTypeIndex = i;
+            break;
+        }
+    }
+    ASSERT_NE(32, mai.memoryTypeIndex);
+
+    // Import w/ non-dedicated memory allocation
+
+    // Import requires format AHB_FMT_BLOB and usage AHB_USAGE_GPU_DATA_BUFFER
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02384");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    // Allocation size mismatch
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    recreate_ahb();
+    mai.allocationSize = ahb_props.allocationSize + 1;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-allocationSize-02383");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    mai.allocationSize = ahb_props.allocationSize;
+    reset_mem();
+
+    // memoryTypeIndex mismatch
+    mai.memoryTypeIndex++;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    mai.memoryTypeIndex--;
+    reset_mem();
+
+    // Insert dedicated image memory allocation to mai chain
+    VkMemoryDedicatedAllocateInfo mdai = {};
+    mdai.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+    mdai.image = img;
+    mdai.buffer = VK_NULL_HANDLE;
+    mdai.pNext = mai.pNext;
+    mai.pNext = &mdai;
+
+    // Dedicated allocation with unmatched usage bits
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
+    recreate_ahb();
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02390");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    // Dedicated allocation with incomplete mip chain
+    reset_img();
+    ici.mipLevels = 2;
+    vkCreateImage(dev, &ici, NULL, &img);
+    mdai.image = img;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE;
+    recreate_ahb();
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02389");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    // Dedicated allocation with mis-matched dimension
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ahb_desc.height = 32;
+    ahb_desc.width = 128;
+    recreate_ahb();
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02388");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    // Dedicated allocation with mis-matched VkFormat
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ahb_desc.height = 64;
+    ahb_desc.width = 64;
+    recreate_ahb();
+    ici.mipLevels = 1;
+    ici.format = VK_FORMAT_B8G8R8A8_UNORM;
+    ici.pNext = NULL;
+    VkImage img2;
+    vkCreateImage(dev, &ici, NULL, &img2);
+    mdai.image = img2;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02387");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    vkDestroyImage(dev, img2, NULL);
+    mdai.image = img;
+    reset_mem();
+
+    // Missing required ahb usage
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884");
+    recreate_ahb();
+    m_errorMonitor->VerifyFound();
+
+    // Dedicated allocation with missing usage bits
+    // Setting up this test also triggers a slew of others
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02390");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-allocationSize-02383");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884");
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02386");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    // Non-import allocation - replace import struct in chain with export struct
+    VkExportMemoryAllocateInfo emai = {};
+    emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
+    emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+    mai.pNext = &emai;
+    emai.pNext = &mdai;  // still dedicated
+    mdai.pNext = nullptr;
+
+    // Export with allocation size non-zero
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    recreate_ahb();
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-01874");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+    reset_mem();
+
+    AHardwareBuffer_release(ahb);
+    reset_mem();
+    reset_img();
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferCreateYCbCrSampler) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer YCbCr sampler creation.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE;
+    VkSamplerYcbcrConversionCreateInfo sycci = {};
+    sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
+    sycci.format = VK_FORMAT_UNDEFINED;
+    sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+    sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904");
+    vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv);
+    m_errorMonitor->VerifyFound();
+
+    VkExternalFormatANDROID efa = {};
+    efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+    sycci.format = VK_FORMAT_R8G8B8A8_UNORM;
+    sycci.pNext = &efa;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904");
+    vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv);
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferPhysDevImageFormatProp2) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer GetPhysicalDeviceImageFormatProperties.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping test\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+
+    if ((m_instance_api_version < VK_API_VERSION_1_1) &&
+        !InstanceExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        printf("%s %s extension not supported, skipping test\n", kSkipPrefix,
+               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        return;
+    }
+
+    VkImageFormatProperties2 ifp = {};
+    ifp.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+    VkPhysicalDeviceImageFormatInfo2 pdifi = {};
+    pdifi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+    pdifi.format = VK_FORMAT_R8G8B8A8_UNORM;
+    pdifi.tiling = VK_IMAGE_TILING_OPTIMAL;
+    pdifi.type = VK_IMAGE_TYPE_2D;
+    pdifi.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    VkAndroidHardwareBufferUsageANDROID ahbu = {};
+    ahbu.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+    ahbu.androidHardwareBufferUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ifp.pNext = &ahbu;
+
+    // AHB_usage chained to input without a matching external image format struc chained to output
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868");
+    vkGetPhysicalDeviceImageFormatProperties2(m_device->phy().handle(), &pdifi, &ifp);
+    m_errorMonitor->VerifyFound();
+
+    // output struct chained, but does not include VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID usage
+    VkPhysicalDeviceExternalImageFormatInfo pdeifi = {};
+    pdeifi.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+    pdeifi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
+    pdifi.pNext = &pdeifi;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868");
+    vkGetPhysicalDeviceImageFormatProperties2(m_device->phy().handle(), &pdifi, &ifp);
+    m_errorMonitor->VerifyFound();
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferCreateImageView) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer image view creation.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    // Expect no validation errors during setup
+    m_errorMonitor->ExpectSuccess();
+
+    // Allocate an AHB and fetch its properties
+    AHardwareBuffer *ahb = nullptr;
+    AHardwareBuffer_Desc ahb_desc = {};
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    ahb_desc.width = 64;
+    ahb_desc.height = 64;
+    ahb_desc.layers = 1;
+    AHardwareBuffer_allocate(&ahb_desc, &ahb);
+
+    // Retrieve AHB properties to make it's external format 'known'
+    VkAndroidHardwareBufferFormatPropertiesANDROID ahb_fmt_props = {};
+    ahb_fmt_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
+    VkAndroidHardwareBufferPropertiesANDROID ahb_props = {};
+    ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
+    ahb_props.pNext = &ahb_fmt_props;
+    PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps =
+        (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID");
+    ASSERT_TRUE(pfn_GetAHBProps != nullptr);
+    pfn_GetAHBProps(dev, ahb, &ahb_props);
+    AHardwareBuffer_release(ahb);
+
+    // Give image an external format
+    VkExternalFormatANDROID efa = {};
+    efa.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+
+    // Create the image
+    VkImage img = VK_NULL_HANDLE;
+    VkImageCreateInfo ici = {};
+    ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    ici.pNext = &efa;
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.arrayLayers = 1;
+    ici.extent = {64, 64, 1};
+    ici.format = VK_FORMAT_UNDEFINED;
+    ici.mipLevels = 1;
+    ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    ici.samples = VK_SAMPLE_COUNT_1_BIT;
+    ici.tiling = VK_IMAGE_TILING_OPTIMAL;
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+    vkCreateImage(dev, &ici, NULL, &img);
+
+    // Set up memory allocation
+    VkDeviceMemory img_mem = VK_NULL_HANDLE;
+    VkMemoryAllocateInfo mai = {};
+    mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mai.allocationSize = 64 * 64 * 4;
+    mai.memoryTypeIndex = 0;
+    vkAllocateMemory(dev, &mai, NULL, &img_mem);
+
+    // Bind image to memory
+    vkBindImageMemory(dev, img, img_mem, 0);
+
+    // Create a YCbCr conversion, with different external format, chain to view
+    VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE;
+    VkSamplerYcbcrConversionCreateInfo sycci = {};
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+    sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
+    sycci.pNext = &efa;
+    sycci.format = VK_FORMAT_UNDEFINED;
+    sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+    sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+    vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv);
+    VkSamplerYcbcrConversionInfo syci = {};
+    syci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
+    syci.conversion = ycbcr_conv;
+
+    // Create a view
+    VkImageView image_view = VK_NULL_HANDLE;
+    VkImageViewCreateInfo ivci = {};
+    ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    ivci.pNext = &syci;
+    ivci.image = img;
+    ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    ivci.format = VK_FORMAT_UNDEFINED;
+    ivci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
+
+    auto reset_view = [&image_view, dev]() {
+        if (VK_NULL_HANDLE != image_view) vkDestroyImageView(dev, image_view, NULL);
+        image_view = VK_NULL_HANDLE;
+    };
+
+    // Up to this point, no errors expected
+    m_errorMonitor->VerifyNotFound();
+
+    // Chained ycbcr conversion has different (external) format than image
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02400");
+    // Also causes "unsupported format" - should be removed in future spec update
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-None-02273");
+    vkCreateImageView(dev, &ivci, NULL, &image_view);
+    m_errorMonitor->VerifyFound();
+
+    reset_view();
+    vkDestroySamplerYcbcrConversion(dev, ycbcr_conv, NULL);
+    efa.externalFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+    vkCreateSamplerYcbcrConversion(dev, &sycci, NULL, &ycbcr_conv);
+    syci.conversion = ycbcr_conv;
+
+    // View component swizzle not IDENTITY
+    ivci.components.r = VK_COMPONENT_SWIZZLE_B;
+    ivci.components.b = VK_COMPONENT_SWIZZLE_R;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02401");
+    // Also causes "unsupported format" - should be removed in future spec update
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-None-02273");
+    vkCreateImageView(dev, &ivci, NULL, &image_view);
+    m_errorMonitor->VerifyFound();
+
+    reset_view();
+    ivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    ivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+    // View with external format, when format is not UNDEFINED
+    ivci.format = VK_FORMAT_R5G6B5_UNORM_PACK16;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-02399");
+    // Also causes "view format different from image format"
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkImageViewCreateInfo-image-01019");
+    vkCreateImageView(dev, &ivci, NULL, &image_view);
+    m_errorMonitor->VerifyFound();
+
+    reset_view();
+    vkDestroySamplerYcbcrConversion(dev, ycbcr_conv, NULL);
+    vkDestroyImageView(dev, image_view, NULL);
+    vkDestroyImage(dev, img, NULL);
+    vkFreeMemory(dev, img_mem, NULL);
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferImportBuffer) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer import as buffer.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkDeviceMemory mem_handle = VK_NULL_HANDLE;
+    auto reset_mem = [&mem_handle, dev]() {
+        if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL);
+        mem_handle = VK_NULL_HANDLE;
+    };
+
+    PFN_vkGetAndroidHardwareBufferPropertiesANDROID pfn_GetAHBProps =
+        (PFN_vkGetAndroidHardwareBufferPropertiesANDROID)vkGetDeviceProcAddr(dev, "vkGetAndroidHardwareBufferPropertiesANDROID");
+    ASSERT_TRUE(pfn_GetAHBProps != nullptr);
+
+    // AHB structs
+    AHardwareBuffer *ahb = nullptr;
+    AHardwareBuffer_Desc ahb_desc = {};
+    VkAndroidHardwareBufferPropertiesANDROID ahb_props = {};
+    ahb_props.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
+    VkImportAndroidHardwareBufferInfoANDROID iahbi = {};
+    iahbi.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
+
+    // Allocate an AHardwareBuffer
+    ahb_desc.format = AHARDWAREBUFFER_FORMAT_BLOB;
+    ahb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE;
+    ahb_desc.width = 512;
+    ahb_desc.height = 1;
+    ahb_desc.layers = 1;
+    AHardwareBuffer_allocate(&ahb_desc, &ahb);
+    pfn_GetAHBProps(dev, ahb, &ahb_props);
+    iahbi.buffer = ahb;
+
+    // Create export and import buffers
+    VkExternalMemoryBufferCreateInfo ext_buf_info = {};
+    ext_buf_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR;
+    ext_buf_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
+
+    VkBufferCreateInfo bci = {};
+    bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    bci.pNext = &ext_buf_info;
+    bci.size = ahb_props.allocationSize;
+    bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+
+    VkBuffer buf = VK_NULL_HANDLE;
+    vkCreateBuffer(dev, &bci, NULL, &buf);
+    VkMemoryRequirements mem_reqs;
+    vkGetBufferMemoryRequirements(dev, buf, &mem_reqs);
+
+    // Allocation info
+    VkMemoryAllocateInfo mai = vk_testing::DeviceMemory::get_resource_alloc_info(*m_device, mem_reqs, 0);
+    mai.pNext = &iahbi;  // Chained import struct
+
+    // Import as buffer requires format AHB_FMT_BLOB and usage AHB_USAGE_GPU_DATA_BUFFER
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881");
+    // Also causes "non-dedicated allocation format/usage" error
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkMemoryAllocateInfo-pNext-02384");
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    m_errorMonitor->VerifyFound();
+
+    AHardwareBuffer_release(ahb);
+    reset_mem();
+    vkDestroyBuffer(dev, buf, NULL);
+}
+
+TEST_F(VkLayerTest, AndroidHardwareBufferExporttBuffer) {
+    TEST_DESCRIPTION("Verify AndroidHardwareBuffer export memory as AHB.");
+
+    SetTargetApiVersion(VK_API_VERSION_1_1);
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if ((DeviceExtensionSupported(gpu(), nullptr, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) &&
+        // Also skip on devices that advertise AHB, but not the pre-requisite foreign_queue extension
+        (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME))) {
+        m_device_extension_names.push_back(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
+        m_device_extension_names.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+    } else {
+        printf("%s %s extension not supported, skipping tests\n", kSkipPrefix,
+               VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    VkDevice dev = m_device->device();
+
+    VkDeviceMemory mem_handle = VK_NULL_HANDLE;
+
+    // Allocate device memory, no linked export struct indicating AHB handle type
+    VkMemoryAllocateInfo mai = {};
+    mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mai.allocationSize = 65536;
+    mai.memoryTypeIndex = 0;
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+
+    PFN_vkGetMemoryAndroidHardwareBufferANDROID pfn_GetMemAHB =
+        (PFN_vkGetMemoryAndroidHardwareBufferANDROID)vkGetDeviceProcAddr(dev, "vkGetMemoryAndroidHardwareBufferANDROID");
+    ASSERT_TRUE(pfn_GetMemAHB != nullptr);
+
+    VkMemoryGetAndroidHardwareBufferInfoANDROID mgahbi = {};
+    mgahbi.sType = VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
+    mgahbi.memory = mem_handle;
+    AHardwareBuffer *ahb = nullptr;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882");
+    pfn_GetMemAHB(dev, &mgahbi, &ahb);
+    m_errorMonitor->VerifyFound();
+
+    if (ahb) AHardwareBuffer_release(ahb);
+    ahb = nullptr;
+    if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL);
+    mem_handle = VK_NULL_HANDLE;
+
+    // Add an export struct with AHB handle type to allocation info
+    VkExportMemoryAllocateInfo emai = {};
+    emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
+    emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+    mai.pNext = &emai;
+
+    // Create an image, do not bind memory
+    VkImage img = VK_NULL_HANDLE;
+    VkImageCreateInfo ici = {};
+    ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    ici.imageType = VK_IMAGE_TYPE_2D;
+    ici.arrayLayers = 1;
+    ici.extent = {128, 128, 1};
+    ici.format = VK_FORMAT_R8G8B8A8_UNORM;
+    ici.mipLevels = 1;
+    ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    ici.samples = VK_SAMPLE_COUNT_1_BIT;
+    ici.tiling = VK_IMAGE_TILING_OPTIMAL;
+    ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+    vkCreateImage(dev, &ici, NULL, &img);
+    ASSERT_TRUE(VK_NULL_HANDLE != img);
+
+    // Add image to allocation chain as dedicated info, re-allocate
+    VkMemoryDedicatedAllocateInfo mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO};
+    mdai.image = img;
+    emai.pNext = &mdai;
+    mai.allocationSize = 0;
+    vkAllocateMemory(dev, &mai, NULL, &mem_handle);
+    mgahbi.memory = mem_handle;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                         "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883");
+    pfn_GetMemAHB(dev, &mgahbi, &ahb);
+    m_errorMonitor->VerifyFound();
+
+    if (ahb) AHardwareBuffer_release(ahb);
+    if (VK_NULL_HANDLE != mem_handle) vkFreeMemory(dev, mem_handle, NULL);
+    vkDestroyImage(dev, img, NULL);
+}
+
+#endif  // VK_USE_PLATFORM_ANDROID_KHR
+
+TEST_F(VkLayerTest, ViewportSwizzleNV) {
+    TEST_DESCRIPTION("Verify VK_NV_viewprot_swizzle.");
+
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+
+    if (DeviceExtensionSupported(gpu(), nullptr, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME)) {
+        m_device_extension_names.push_back(VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME);
+    } else {
+        printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME);
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    VkViewportSwizzleNV invalid_swizzles = {
+        VkViewportCoordinateSwizzleNV(-1),
+        VkViewportCoordinateSwizzleNV(-1),
+        VkViewportCoordinateSwizzleNV(-1),
+        VkViewportCoordinateSwizzleNV(-1),
+    };
+
+    VkPipelineViewportSwizzleStateCreateInfoNV vp_swizzle_state = {
+        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV};
+    vp_swizzle_state.viewportCount = 1;
+    vp_swizzle_state.pViewportSwizzles = &invalid_swizzles;
+
+    const std::vector<std::string> expected_vuids = {"VUID-VkViewportSwizzleNV-x-parameter", "VUID-VkViewportSwizzleNV-y-parameter",
+                                                     "VUID-VkViewportSwizzleNV-z-parameter",
+                                                     "VUID-VkViewportSwizzleNV-w-parameter"};
+
+    auto break_swizzles = [&vp_swizzle_state](CreatePipelineHelper &helper) { helper.vp_state_ci_.pNext = &vp_swizzle_state; };
+
+    CreatePipelineHelper::OneshotTest(*this, break_swizzles, VK_DEBUG_REPORT_ERROR_BIT_EXT, expected_vuids);
+
+    struct TestCase {
+        VkBool32 rasterizerDiscardEnable;
+        uint32_t vp_count;
+        uint32_t swizzel_vp_count;
+        bool positive;
+    };
+
+    const std::array<TestCase, 3> test_cases = {{{VK_TRUE, 1, 2, true}, {VK_FALSE, 1, 1, true}, {VK_FALSE, 1, 2, false}}};
+
+    std::array<VkViewportSwizzleNV, 2> swizzles = {
+        {{VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,
+          VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV},
+         {VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,
+          VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV}}};
+
+    for (const auto &test_case : test_cases) {
+        assert(test_case.vp_count <= swizzles.size());
+
+        vp_swizzle_state.viewportCount = test_case.swizzel_vp_count;
+        vp_swizzle_state.pViewportSwizzles = swizzles.data();
+
+        auto break_vp_count = [&vp_swizzle_state, &test_case](CreatePipelineHelper &helper) {
+            helper.rs_state_ci_.rasterizerDiscardEnable = test_case.rasterizerDiscardEnable;
+            helper.vp_state_ci_.viewportCount = test_case.vp_count;
+
+            helper.vp_state_ci_.pNext = &vp_swizzle_state;
+        };
+
+        CreatePipelineHelper::OneshotTest(*this, break_vp_count, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                          "VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-01215",
+                                          test_case.positive);
+    }
+}
+
+TEST_F(VkLayerTest, BufferDeviceAddressEXT) {
+    TEST_DESCRIPTION("Test VK_EXT_buffer_device_address.");
+
+    if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    } else {
+        printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix,
+               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    std::array<const char *, 1> required_device_extensions = {{VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME}};
+    for (auto device_extension : required_device_extensions) {
+        if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
+            m_device_extension_names.push_back(device_extension);
+        } else {
+            printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension);
+            return;
+        }
+    }
+
+    PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR =
+        (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR");
+    ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
+
+    // Create a device that enables buffer_device_address
+    auto buffer_device_address_features = lvl_init_struct<VkPhysicalDeviceBufferAddressFeaturesEXT>();
+    auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&buffer_device_address_features);
+    vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
+    buffer_device_address_features.bufferDeviceAddressCaptureReplay = VK_FALSE;
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT =
+        (PFN_vkGetBufferDeviceAddressEXT)vkGetInstanceProcAddr(instance(), "vkGetBufferDeviceAddressEXT");
+
+    VkBufferCreateInfo buffer_create_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
+    buffer_create_info.size = sizeof(uint32_t);
+    buffer_create_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT;
+    buffer_create_info.flags = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT;
+    VkBuffer buffer;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferCreateInfo-flags-02605");
+    VkResult result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    m_errorMonitor->VerifyFound();
+    if (result == VK_SUCCESS) {
+        vkDestroyBuffer(m_device->device(), buffer, NULL);
+    }
+
+    buffer_create_info.flags = 0;
+    VkBufferDeviceAddressCreateInfoEXT addr_ci = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT};
+    addr_ci.deviceAddress = 1;
+    buffer_create_info.pNext = &addr_ci;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferCreateInfo-deviceAddress-02604");
+    result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    m_errorMonitor->VerifyFound();
+    if (result == VK_SUCCESS) {
+        vkDestroyBuffer(m_device->device(), buffer, NULL);
+    }
+
+    buffer_create_info.pNext = nullptr;
+    result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    ASSERT_VK_SUCCESS(result);
+
+    VkBufferDeviceAddressInfoEXT info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT};
+    info.buffer = buffer;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferDeviceAddressInfoEXT-buffer-02600");
+    vkGetBufferDeviceAddressEXT(m_device->device(), &info);
+    m_errorMonitor->VerifyFound();
+
+    vkDestroyBuffer(m_device->device(), buffer, NULL);
+}
+
+TEST_F(VkLayerTest, BufferDeviceAddressEXTDisabled) {
+    TEST_DESCRIPTION("Test VK_EXT_buffer_device_address.");
+
+    if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+        m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    } else {
+        printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix,
+               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+        return;
+    }
+    ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+    std::array<const char *, 1> required_device_extensions = {{VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME}};
+    for (auto device_extension : required_device_extensions) {
+        if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
+            m_device_extension_names.push_back(device_extension);
+        } else {
+            printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension);
+            return;
+        }
+    }
+
+    PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR =
+        (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR");
+    ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
+
+    // Create a device that disables buffer_device_address
+    auto buffer_device_address_features = lvl_init_struct<VkPhysicalDeviceBufferAddressFeaturesEXT>();
+    auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&buffer_device_address_features);
+    vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
+    buffer_device_address_features.bufferDeviceAddress = VK_FALSE;
+    buffer_device_address_features.bufferDeviceAddressCaptureReplay = VK_FALSE;
+
+    ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+    PFN_vkGetBufferDeviceAddressEXT vkGetBufferDeviceAddressEXT =
+        (PFN_vkGetBufferDeviceAddressEXT)vkGetInstanceProcAddr(instance(), "vkGetBufferDeviceAddressEXT");
+
+    VkBufferCreateInfo buffer_create_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
+    buffer_create_info.size = sizeof(uint32_t);
+    buffer_create_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT;
+    VkBuffer buffer;
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferCreateInfo-usage-02606");
+    VkResult result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    m_errorMonitor->VerifyFound();
+    if (result == VK_SUCCESS) {
+        vkDestroyBuffer(m_device->device(), buffer, NULL);
+    }
+
+    buffer_create_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+    result = vkCreateBuffer(m_device->device(), &buffer_create_info, nullptr, &buffer);
+    ASSERT_VK_SUCCESS(result);
+
+    VkBufferDeviceAddressInfoEXT info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT};
+    info.buffer = buffer;
+
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkGetBufferDeviceAddressEXT-None-02598");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferDeviceAddressInfoEXT-buffer-02601");
+    m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-VkBufferDeviceAddressInfoEXT-buffer-02600");
+    vkGetBufferDeviceAddressEXT(m_device->device(), &info);
+    m_errorMonitor->VerifyFound();
+
+    vkDestroyBuffer(m_device->device(), buffer, NULL);
+}
 
 #if defined(ANDROID) && defined(VALIDATION_APK)
 const char *appTag = "VulkanLayerValidationTests";
diff --git a/tests/layers/CMakeLists.txt b/tests/layers/CMakeLists.txt
index 63c833f..bd66b6d 100644
--- a/tests/layers/CMakeLists.txt
+++ b/tests/layers/CMakeLists.txt
@@ -69,7 +69,7 @@
         set_target_properties(copy-${target}-def-file PROPERTIES FOLDER ${LAYERS_HELPER_FOLDER})
 
         add_library(VkLayer_${target} SHARED ${ARGN} VkLayer_${target}.def)
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VkLayer_utils)
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
         target_compile_definitions(VkLayer_${target} PRIVATE "_CRT_SECURE_NO_WARNINGS")
         target_compile_options(VkLayer_${target} PRIVATE $<$<CONFIG:Debug>:/bigobj>)
@@ -77,7 +77,7 @@
 elseif(APPLE)
     macro(AddVkLayer target)
         add_library(VkLayer_${target} SHARED ${ARGN})
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VkLayer_utils)
         set_target_properties(VkLayer_${target} PROPERTIES LINK_FLAGS "-Wl")
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
         target_compile_options(VkLayer_${target} PRIVATE "-Wpointer-arith" "-Wno-unused-function")
@@ -85,7 +85,7 @@
 else(UNIX AND NOT APPLE) # i.e.: Linux
     macro(AddVkLayer target)
         add_library(VkLayer_${target} SHARED ${ARGN})
-        add_dependencies(VkLayer_${target} generate_helper_files VkLayer_utils)
+        add_dependencies(VkLayer_${target} VulkanVL_generate_helper_files VkLayer_utils)
         set_target_properties(VkLayer_${target} PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic")
         target_link_libraries(VkLayer_${target} PRIVATE VkLayer_utils)
         target_compile_options(VkLayer_${target} PRIVATE "-Wpointer-arith" "-Wno-unused-function")
@@ -108,7 +108,12 @@
 
 if(WIN32)
     # For Windows, copy necessary gtest DLLs to the right spot for the vk_layer_tests...
-    file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/*device_profile_api.* SRC_LAYER)
+    if (MSVC_IDE)
+        file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/*device_profile_api.* SRC_LAYER)
+    else()
+        file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/*device_profile_api.* SRC_LAYER)
+    endif()
+
     file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/windows/${TEST_LAYER_NAME}.json SRC_JSON)
     file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR}/layers/$<CONFIG> DST_LAYER)
     add_custom_command(TARGET ${TEST_LAYER_NAME} POST_BUILD
diff --git a/tests/layers/linux/VkLayer_device_profile_api.json b/tests/layers/linux/VkLayer_device_profile_api.json
index 8e2e2f8..3f837b8 100644
--- a/tests/layers/linux/VkLayer_device_profile_api.json
+++ b/tests/layers/linux/VkLayer_device_profile_api.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_device_profile_api",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_device_profile_api.so",
-        "api_version": "1.1.83",
+        "api_version": "1.1.101",
         "implementation_version": "2",
         "description": "LunarG Device Profile Api Layer",
         "device_extensions": [
diff --git a/tests/layers/macos/VkLayer_device_profile_api.json b/tests/layers/macos/VkLayer_device_profile_api.json
index b6aa5c6..3600845 100644
--- a/tests/layers/macos/VkLayer_device_profile_api.json
+++ b/tests/layers/macos/VkLayer_device_profile_api.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_device_profile_api",
         "type": "GLOBAL",
         "library_path": "./libVkLayer_device_profile_api.dylib",
-        "api_version": "1.0.69",
+        "api_version": "1.0.101",
         "implementation_version": "2",
         "description": "LunarG Device Profile Api Layer",
         "device_extensions": [
diff --git a/tests/layers/windows/VkLayer_device_profile_api.json b/tests/layers/windows/VkLayer_device_profile_api.json
index 09e1ee9..0e890c1 100644
--- a/tests/layers/windows/VkLayer_device_profile_api.json
+++ b/tests/layers/windows/VkLayer_device_profile_api.json
@@ -4,7 +4,7 @@
         "name": "VK_LAYER_LUNARG_device_profile_api",
         "type": "GLOBAL",
         "library_path": ".\\VkLayer_device_profile_api.dll",
-        "api_version": "1.1.83",
+        "api_version": "1.1.101",
         "implementation_version": "2",
         "description": "LunarG Device Profile Api Layer",
         "device_extensions": [
diff --git a/tests/vkrenderframework.cpp b/tests/vkrenderframework.cpp
index 094199a..63b8f7b 100644
--- a/tests/vkrenderframework.cpp
+++ b/tests/vkrenderframework.cpp
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2015-2017 The Khronos Group Inc.
- * Copyright (c) 2015-2017 Valve Corporation
- * Copyright (c) 2015-2017 LunarG, Inc.
- * Copyright (c) 2015-2017 Google, Inc.
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ * Copyright (c) 2015-2019 Google, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -178,7 +178,93 @@
     return ext_found;
 }
 
-void VkRenderFramework::InitFramework(PFN_vkDebugReportCallbackEXT dbgFunction, void *userData) {
+// WARNING:  The DevSim layer can override the properties that are tested here, making the result of
+// this function dubious when DevSim is active.
+bool VkRenderFramework::DeviceIsMockICD() {
+    VkPhysicalDeviceProperties props = vk_testing::PhysicalDevice(gpu()).properties();
+    if ((props.vendorID == 0xba5eba11) && (props.deviceID == 0xf005ba11) && (0 == strcmp("Vulkan Mock Device", props.deviceName))) {
+        return true;
+    }
+    return false;
+}
+
+// Render into a RenderTarget and read the pixels back to see if the device can really draw.
+// Note: This cannot be called from inside an initialized VkRenderFramework because frameworks cannot be "nested".
+// It is best to call it before "Init()".
+bool VkRenderFramework::DeviceCanDraw() {
+    InitFramework(NULL, NULL);
+    InitState(NULL, NULL, 0);
+    InitViewport();
+    InitRenderTarget();
+
+    // Draw a triangle that covers the entire viewport.
+    char const *vsSource =
+        "#version 450\n"
+        "\n"
+        "vec2 vertices[3];\n"
+        "void main() { \n"
+        "  vertices[0] = vec2(-10.0, -10.0);\n"
+        "  vertices[1] = vec2( 10.0, -10.0);\n"
+        "  vertices[2] = vec2( 0.0,   10.0);\n"
+        "  gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
+        "}\n";
+    // Draw with a solid color.
+    char const *fsSource =
+        "#version 450\n"
+        "\n"
+        "layout(location=0) out vec4 color;\n"
+        "void main() {\n"
+        "   color = vec4(32.0/255.0);\n"
+        "}\n";
+    VkShaderObj *vs = new VkShaderObj(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this);
+    VkShaderObj *fs = new VkShaderObj(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this);
+
+    VkPipelineObj *pipe = new VkPipelineObj(m_device);
+    pipe->AddShader(vs);
+    pipe->AddShader(fs);
+    pipe->AddDefaultColorAttachment();
+
+    VkDescriptorSetObj *descriptorSet = new VkDescriptorSetObj(m_device);
+    descriptorSet->CreateVKDescriptorSet(m_commandBuffer);
+
+    pipe->CreateVKPipeline(descriptorSet->GetPipelineLayout(), renderPass());
+
+    m_commandBuffer->begin();
+    m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
+
+    vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe->handle());
+    m_commandBuffer->BindDescriptorSet(*descriptorSet);
+
+    VkViewport viewport = m_viewports[0];
+    VkRect2D scissors = m_scissors[0];
+
+    vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
+    vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissors);
+
+    vkCmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
+
+    m_commandBuffer->EndRenderPass();
+    m_commandBuffer->end();
+
+    VkSubmitInfo submit_info = {};
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &m_commandBuffer->handle();
+
+    vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+    vkQueueWaitIdle(m_device->m_queue);
+
+    auto pixels = m_renderTargets[0]->Read();
+
+    delete descriptorSet;
+    delete pipe;
+    delete fs;
+    delete vs;
+    ShutdownFramework();
+    return pixels[0][0] == 0x20202020;
+}
+
+void VkRenderFramework::InitFramework(PFN_vkDebugReportCallbackEXT dbgFunction, void *userData, void *instance_pnext) {
     // Only enable device profile layer by default if devsim is not enabled
     if (!VkTestFramework::m_devsim_layer && InstanceLayerSupported("VK_LAYER_LUNARG_device_profile_api")) {
         m_instance_layer_names.push_back("VK_LAYER_LUNARG_device_profile_api");
@@ -211,7 +297,7 @@
     VkResult U_ASSERT_ONLY err;
 
     instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
-    instInfo.pNext = NULL;
+    instInfo.pNext = instance_pnext;
     instInfo.pApplicationInfo = &app_info;
     instInfo.enabledLayerCount = m_instance_layer_names.size();
     instInfo.ppEnabledLayerNames = m_instance_layer_names.data();
@@ -267,19 +353,28 @@
     if (!this->inst) return;
 
     delete m_commandBuffer;
+    m_commandBuffer = nullptr;
     delete m_commandPool;
+    m_commandPool = nullptr;
     if (m_framebuffer) vkDestroyFramebuffer(device(), m_framebuffer, NULL);
+    m_framebuffer = VK_NULL_HANDLE;
     if (m_renderPass) vkDestroyRenderPass(device(), m_renderPass, NULL);
+    m_renderPass = VK_NULL_HANDLE;
 
     if (m_globalMsgCallback) m_DestroyDebugReportCallback(this->inst, m_globalMsgCallback, NULL);
+    m_globalMsgCallback = VK_NULL_HANDLE;
     if (m_devMsgCallback) m_DestroyDebugReportCallback(this->inst, m_devMsgCallback, NULL);
+    m_devMsgCallback = VK_NULL_HANDLE;
 
     m_renderTargets.clear();
 
     delete m_depthStencil;
+    m_depthStencil = nullptr;
 
     // reset the driver
     delete m_device;
+    m_device = nullptr;
+
     if (this->inst) vkDestroyInstance(this->inst, NULL);
     this->inst = (VkInstance)0;  // In case we want to re-initialize
 }
@@ -298,7 +393,7 @@
     *props = vk_testing::PhysicalDevice(gpu()).properties();
 }
 
-void VkRenderFramework::InitState(VkPhysicalDeviceFeatures *features, VkPhysicalDeviceFeatures2 *features2,
+void VkRenderFramework::InitState(VkPhysicalDeviceFeatures *features, void *create_device_pnext,
                                   const VkCommandPoolCreateFlags flags) {
     // Remove any unsupported device extension names from list
     for (auto ext = m_device_extension_names.begin(); ext != m_device_extension_names.end();) {
@@ -321,7 +416,7 @@
         }
     }
 
-    m_device = new VkDeviceObj(0, objs[0], m_device_extension_names, features, features2);
+    m_device = new VkDeviceObj(0, objs[0], m_device_extension_names, features, create_device_pnext);
     m_device->SetDeviceQueue();
 
     m_depthStencil = new VkDepthStencilObj(m_device);
@@ -542,9 +637,9 @@
 }
 
 VkDeviceObj::VkDeviceObj(uint32_t id, VkPhysicalDevice obj, std::vector<const char *> &extension_names,
-                         VkPhysicalDeviceFeatures *features, VkPhysicalDeviceFeatures2 *features2)
+                         VkPhysicalDeviceFeatures *features, void *create_device_pnext)
     : vk_testing::Device(obj), id(id) {
-    init(extension_names, features, features2);
+    init(extension_names, features, create_device_pnext);
 
     props = phy().properties();
     queue_props = phy().queue_properties();
@@ -635,7 +730,7 @@
 
     m_layout_bindings.push_back(binding);
     m_type_counts[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] += binding.descriptorCount;
-    VkDescriptorImageInfo tmp = texture->m_imageInfo;
+    VkDescriptorImageInfo tmp = texture->DescriptorImageInfo();
     tmp.sampler = sampler->handle();
     m_imageSamplerDescriptors.push_back(tmp);
 
@@ -1067,6 +1162,73 @@
     return VK_SUCCESS;
 }
 
+// Same as CopyImage, but in the opposite direction
+VkResult VkImageObj::CopyImageOut(VkImageObj &dst_image) {
+    VkImageLayout src_image_layout, dest_image_layout;
+
+    VkCommandPoolObj pool(m_device, m_device->graphics_queue_node_index_);
+    VkCommandBufferObj cmd_buf(m_device, &pool);
+
+    cmd_buf.begin();
+
+    src_image_layout = this->Layout();
+    this->SetLayout(&cmd_buf, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+    dest_image_layout = (dst_image.Layout() == VK_IMAGE_LAYOUT_UNDEFINED) ? VK_IMAGE_LAYOUT_GENERAL : this->Layout();
+    dst_image.SetLayout(&cmd_buf, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+    VkImageCopy copy_region = {};
+    copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    copy_region.srcSubresource.baseArrayLayer = 0;
+    copy_region.srcSubresource.mipLevel = 0;
+    copy_region.srcSubresource.layerCount = 1;
+    copy_region.srcOffset.x = 0;
+    copy_region.srcOffset.y = 0;
+    copy_region.srcOffset.z = 0;
+    copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    copy_region.dstSubresource.baseArrayLayer = 0;
+    copy_region.dstSubresource.mipLevel = 0;
+    copy_region.dstSubresource.layerCount = 1;
+    copy_region.dstOffset.x = 0;
+    copy_region.dstOffset.y = 0;
+    copy_region.dstOffset.z = 0;
+    copy_region.extent = dst_image.extent();
+
+    vkCmdCopyImage(cmd_buf.handle(), handle(), Layout(), dst_image.handle(), dst_image.Layout(), 1, &copy_region);
+
+    this->SetLayout(&cmd_buf, VK_IMAGE_ASPECT_COLOR_BIT, src_image_layout);
+
+    dst_image.SetLayout(&cmd_buf, VK_IMAGE_ASPECT_COLOR_BIT, dest_image_layout);
+
+    cmd_buf.end();
+
+    cmd_buf.QueueCommandBuffer();
+
+    return VK_SUCCESS;
+}
+
+// Return 16x16 pixel block
+std::array<std::array<uint32_t, 16>, 16> VkImageObj::Read() {
+    VkImageObj stagingImage(m_device);
+    VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+    stagingImage.Init(16, 16, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+                      VK_IMAGE_TILING_LINEAR, reqs);
+    stagingImage.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
+    VkSubresourceLayout layout = stagingImage.subresource_layout(subresource(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0));
+    CopyImageOut(stagingImage);
+    void *data = stagingImage.MapMemory();
+    std::array<std::array<uint32_t, 16>, 16> m = {};
+    if (data) {
+        for (uint32_t y = 0; y < stagingImage.extent().height; y++) {
+            uint32_t *row = (uint32_t *)((char *)data + layout.rowPitch * y);
+            for (uint32_t x = 0; x < stagingImage.extent().width; x++) m[y][x] = row[x];
+        }
+    }
+    stagingImage.UnmapMemory();
+    return m;
+}
+
 VkTextureObj::VkTextureObj(VkDeviceObj *device, uint32_t *colors) : VkImageObj(device) {
     m_device = device;
     const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
@@ -1082,8 +1244,6 @@
 
     if (colors == NULL) colors = tex_colors;
 
-    memset(&m_imageInfo, 0, sizeof(m_imageInfo));
-
     VkImageViewCreateInfo view = {};
     view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
     view.pNext = NULL;
@@ -1107,7 +1267,7 @@
     /* create image view */
     view.image = handle();
     m_textureView.init(*m_device, view);
-    m_imageInfo.imageView = m_textureView.handle();
+    m_descriptorImageInfo.imageView = m_textureView.handle();
 
     data = stagingImage.MapMemory();
 
@@ -1190,7 +1350,7 @@
 VkPipelineShaderStageCreateInfo const &VkShaderObj::GetStageCreateInfo() const { return m_stage_info; }
 
 VkShaderObj::VkShaderObj(VkDeviceObj *device, const char *shader_code, VkShaderStageFlagBits stage, VkRenderFramework *framework,
-                         char const *name) {
+                         char const *name, bool debug) {
     VkResult U_ASSERT_ONLY err = VK_SUCCESS;
     std::vector<unsigned int> spv;
     VkShaderModuleCreateInfo moduleCreateInfo;
@@ -1207,7 +1367,7 @@
     moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
     moduleCreateInfo.pNext = nullptr;
 
-    framework->GLSLtoSPV(stage, shader_code, spv);
+    framework->GLSLtoSPV(stage, shader_code, spv, debug);
     moduleCreateInfo.pCode = spv.data();
     moduleCreateInfo.codeSize = spv.size() * sizeof(unsigned int);
     moduleCreateInfo.flags = 0;
diff --git a/tests/vkrenderframework.h b/tests/vkrenderframework.h
index b89eb5c..58a5c44 100644
--- a/tests/vkrenderframework.h
+++ b/tests/vkrenderframework.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015-2017 The Khronos Group Inc.
- * Copyright (c) 2015-2017 Valve Corporation
- * Copyright (c) 2015-2017 LunarG, Inc.
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@
    public:
     VkDeviceObj(uint32_t id, VkPhysicalDevice obj);
     VkDeviceObj(uint32_t id, VkPhysicalDevice obj, std::vector<const char *> &extension_names,
-                VkPhysicalDeviceFeatures *features = nullptr, VkPhysicalDeviceFeatures2KHR *features2 = nullptr);
+                VkPhysicalDeviceFeatures *features = nullptr, void *create_device_pnext = nullptr);
 
     uint32_t QueueFamilyMatching(VkQueueFlags with, VkQueueFlags without, bool all_bits = true);
     uint32_t QueueFamilyWithoutCapabilities(VkQueueFlags capabilities) {
@@ -94,12 +94,12 @@
     void InitRenderTarget(VkImageView *dsBinding);
     void InitRenderTarget(uint32_t targets, VkImageView *dsBinding);
     void DestroyRenderTarget();
-    void InitFramework(PFN_vkDebugReportCallbackEXT = NULL, void *userData = NULL);
+    void InitFramework(PFN_vkDebugReportCallbackEXT = NULL, void *userData = NULL, void *instance_pnext = NULL);
 
     void ShutdownFramework();
     void GetPhysicalDeviceFeatures(VkPhysicalDeviceFeatures *features);
     void GetPhysicalDeviceProperties(VkPhysicalDeviceProperties *props);
-    void InitState(VkPhysicalDeviceFeatures *features = nullptr, VkPhysicalDeviceFeatures2 *features2 = nullptr,
+    void InitState(VkPhysicalDeviceFeatures *features = nullptr, void *create_device_pnext = nullptr,
                    const VkCommandPoolCreateFlags flags = 0);
 
     const VkRenderPassBeginInfo &renderPassBeginInfo() const { return m_renderPassBeginInfo; }
@@ -110,6 +110,8 @@
     bool InstanceExtensionEnabled(const char *name);
     bool DeviceExtensionSupported(VkPhysicalDevice dev, const char *layer, const char *name, uint32_t specVersion = 0);
     bool DeviceExtensionEnabled(const char *name);
+    bool DeviceIsMockICD();
+    bool DeviceCanDraw();
 
    protected:
     VkApplicationInfo app_info;
@@ -281,6 +283,10 @@
 
     VkResult CopyImage(VkImageObj &src_image);
 
+    VkResult CopyImageOut(VkImageObj &dst_image);
+
+    std::array<std::array<uint32_t, 16>, 16> Read();
+
     VkImage image() const { return handle(); }
 
     VkImageView targetView(VkFormat format) {
@@ -320,7 +326,7 @@
    public:
     VkTextureObj(VkDeviceObj *device, uint32_t *colors = NULL);
 
-    VkDescriptorImageInfo m_imageInfo;
+    const VkDescriptorImageInfo &DescriptorImageInfo() const { return m_descriptorImageInfo; }
 
    protected:
     VkDeviceObj *m_device;
@@ -398,7 +404,7 @@
 class VkShaderObj : public vk_testing::ShaderModule {
    public:
     VkShaderObj(VkDeviceObj *device, const char *shaderText, VkShaderStageFlagBits stage, VkRenderFramework *framework,
-                char const *name = "main");
+                char const *name = "main", bool debug = false);
     VkShaderObj(VkDeviceObj *device, const std::string spv_source, VkShaderStageFlagBits stage, VkRenderFramework *framework,
                 char const *name = "main");
     VkPipelineShaderStageCreateInfo const &GetStageCreateInfo() const;
diff --git a/tests/vktestbinding.cpp b/tests/vktestbinding.cpp
index 68e08a8..399442a 100644
--- a/tests/vktestbinding.cpp
+++ b/tests/vktestbinding.cpp
@@ -21,6 +21,7 @@
 
 #include "test_common.h"    // NOEXCEPT macro (must precede vktestbinding.h)
 #include "vktestbinding.h"  // Left for clarity, no harm, already included via test_common.h
+#include "vk_typemap_helper.h"
 #include <algorithm>
 #include <assert.h>
 #include <iostream>
@@ -242,7 +243,7 @@
     vkDestroyDevice(handle(), NULL);
 }
 
-void Device::init(std::vector<const char *> &extensions, VkPhysicalDeviceFeatures *features, VkPhysicalDeviceFeatures2 *features2) {
+void Device::init(std::vector<const char *> &extensions, VkPhysicalDeviceFeatures *features, void *create_device_pnext) {
     // request all queues
     const std::vector<VkQueueFamilyProperties> queue_props = phy_.queue_properties();
     QueueCreateInfoArray queue_info(phy_.queue_properties());
@@ -265,7 +266,7 @@
 
     VkDeviceCreateInfo dev_info = {};
     dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
-    dev_info.pNext = NULL;
+    dev_info.pNext = create_device_pnext;
     dev_info.queueCreateInfoCount = create_queue_infos.size();
     dev_info.pQueueCreateInfos = create_queue_infos.data();
     dev_info.enabledLayerCount = 0;
@@ -276,14 +277,15 @@
     VkPhysicalDeviceFeatures all_features;
     // Let VkPhysicalDeviceFeatures2 take priority over VkPhysicalDeviceFeatures,
     // since it supports extensions
-    if (features2) {
-        dev_info.pNext = features2;
-    } else if (features) {
-        dev_info.pEnabledFeatures = features;
-    } else {
-        // request all supportable features enabled
-        all_features = phy().features();
-        dev_info.pEnabledFeatures = &all_features;
+
+    if (!(lvl_find_in_chain<VkPhysicalDeviceFeatures2>(dev_info.pNext))) {
+        if (features) {
+            dev_info.pEnabledFeatures = features;
+        } else {
+            // request all supportable features enabled
+            all_features = phy().features();
+            dev_info.pEnabledFeatures = &all_features;
+        }
     }
 
     init(dev_info);
diff --git a/tests/vktestbinding.h b/tests/vktestbinding.h
index c244b0e..0b47f02 100644
--- a/tests/vktestbinding.h
+++ b/tests/vktestbinding.h
@@ -196,7 +196,7 @@
     // vkCreateDevice()
     void init(const VkDeviceCreateInfo &info);
     void init(std::vector<const char *> &extensions, VkPhysicalDeviceFeatures *features = nullptr,
-              VkPhysicalDeviceFeatures2 *features2 = nullptr);  // all queues, all extensions, etc
+              void *create_device_pnext = nullptr);  // all queues, all extensions, etc
     void init() {
         std::vector<const char *> extensions;
         init(extensions);
diff --git a/tests/vktestframework.cpp b/tests/vktestframework.cpp
index ba84871..9819a3b 100644
--- a/tests/vktestframework.cpp
+++ b/tests/vktestframework.cpp
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -721,6 +721,30 @@
         case VK_SHADER_STAGE_COMPUTE_BIT:
             return EShLangCompute;
 
+        case VK_SHADER_STAGE_RAYGEN_BIT_NV:
+            return EShLangRayGenNV;
+
+        case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
+            return EShLangAnyHitNV;
+
+        case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
+            return EShLangClosestHitNV;
+
+        case VK_SHADER_STAGE_MISS_BIT_NV:
+            return EShLangMissNV;
+
+        case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
+            return EShLangIntersectNV;
+
+        case VK_SHADER_STAGE_CALLABLE_BIT_NV:
+            return EShLangCallableNV;
+
+        case VK_SHADER_STAGE_TASK_BIT_NV:
+            return EShLangTaskNV;
+
+        case VK_SHADER_STAGE_MESH_BIT_NV:
+            return EShLangMeshNV;
+
         default:
             return EShLangVertex;
     }
@@ -730,7 +754,8 @@
 // Compile a given string containing GLSL into SPV for use by VK
 // Return value of false means an error was encountered.
 //
-bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv) {
+bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv,
+                                bool debug) {
     glslang::TProgram program;
     const char *shaderStrings[1];
 
@@ -743,6 +768,9 @@
     EShMessages messages = EShMsgDefault;
     SetMessageOptions(messages);
     messages = static_cast<EShMessages>(messages | EShMsgSpvRules | EShMsgVulkanRules);
+    if (debug) {
+        messages = static_cast<EShMessages>(messages | EShMsgDebugInfo);
+    }
 
     EShLanguage stage = FindLanguage(shader_type);
     glslang::TShader *shader = new glslang::TShader(stage);
@@ -779,7 +807,11 @@
         program.dumpReflection();
     }
 
-    glslang::GlslangToSpv(*program.getIntermediate(stage), spirv);
+    glslang::SpvOptions spv_options;
+    if (debug) {
+        spv_options.generateDebugInfo = true;
+    }
+    glslang::GlslangToSpv(*program.getIntermediate(stage), spirv, &spv_options);
 
     //
     // Test the different modes of SPIR-V modification
diff --git a/tests/vktestframework.h b/tests/vktestframework.h
index a0f2ff9..c73600f 100644
--- a/tests/vktestframework.h
+++ b/tests/vktestframework.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -67,7 +67,8 @@
     static void InitArgs(int *argc, char *argv[]);
     static void Finish();
 
-    bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spv);
+    bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spv,
+                   bool debug = false);
     bool ASMtoSPV(const spv_target_env target_env, const uint32_t options, const char *pasm, std::vector<unsigned int> &spv);
     static bool m_canonicalize_spv;
     static bool m_strip_spv;
diff --git a/tests/vktestframeworkandroid.cpp b/tests/vktestframeworkandroid.cpp
index 9dbfe36..77e8920 100644
--- a/tests/vktestframeworkandroid.cpp
+++ b/tests/vktestframeworkandroid.cpp
@@ -1,9 +1,9 @@
 //  VK tests
 //
-//  Copyright (c) 2015-2016 The Khronos Group Inc.
-//  Copyright (c) 2015-2016 Valve Corporation
-//  Copyright (c) 2015-2016 LunarG, Inc.
-//  Copyright (c) 2015-2016 Google, Inc.
+//  Copyright (c) 2015-2019 The Khronos Group Inc.
+//  Copyright (c) 2015-2019 Valve Corporation
+//  Copyright (c) 2015-2019 LunarG, Inc.
+//  Copyright (c) 2015-2019 Google, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -77,11 +77,17 @@
 
 // Compile a given string containing GLSL into SPIR-V
 // Return value of false means an error was encountered
-bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv) {
+bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv,
+                                bool debug) {
     // On Android, use shaderc instead.
     shaderc::Compiler compiler;
+    shaderc::CompileOptions options;
+    if (debug) {
+        options.SetOptimizationLevel(shaderc_optimization_level_zero);
+        options.SetGenerateDebugInfo();
+    }
     shaderc::SpvCompilationResult result =
-        compiler.CompileGlslToSpv(pshader, strlen(pshader), MapShadercType(shader_type), "shader");
+        compiler.CompileGlslToSpv(pshader, strlen(pshader), MapShadercType(shader_type), "shader", options);
     if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
         __android_log_print(ANDROID_LOG_ERROR, "VkLayerValidationTest", "GLSLtoSPV compilation failed: %s",
                             result.GetErrorMessage().c_str());
diff --git a/tests/vktestframeworkandroid.h b/tests/vktestframeworkandroid.h
index 7ec4b50..631f8eb 100644
--- a/tests/vktestframeworkandroid.h
+++ b/tests/vktestframeworkandroid.h
@@ -1,9 +1,9 @@
 //  VK tests
 //
-//  Copyright (c) 2015-2016 The Khronos Group Inc.
-//  Copyright (c) 2015-2016 Valve Corporation
-//  Copyright (c) 2015-2016 LunarG, Inc.
-//  Copyright (c) 2015-2016 Google, Inc.
+//  Copyright (c) 2015-2019 The Khronos Group Inc.
+//  Copyright (c) 2015-2019 Valve Corporation
+//  Copyright (c) 2015-2019 LunarG, Inc.
+//  Copyright (c) 2015-2019 Google, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -43,7 +43,8 @@
     static void Finish();
 
     VkFormat GetFormat(VkInstance instance, vk_testing::Device *device);
-    bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spv);
+    bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spv,
+                   bool debug = false);
     bool ASMtoSPV(const spv_target_env target_env, const uint32_t options, const char *pasm, std::vector<unsigned int> &spv);
     static bool m_devsim_layer;
 };