layers: Initial revision of Layer Chassis

This chassis will be used to build a layer or layers containing
zero, one, or multiple layer validation objects.

Change-Id: I88a5ac7f2a320fbfe17fc9fc8f82c2ed7af9a2c3
diff --git a/scripts/layer_chassis_generator.py b/scripts/layer_chassis_generator.py
new file mode 100644
index 0000000..2ca3891
--- /dev/null
+++ b/scripts/layer_chassis_generator.py
@@ -0,0 +1,793 @@
+#!/usr/bin/python3 -i
+#
+# 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>
+#
+# 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']
+
+
+
+
+    inline_custom_source_preamble = """
+// This file is ***GENERATED***.  Do Not Edit.
+// See layer_chassis_generator.py for modifications.
+
+/* 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>
+ */
+
+#include <string.h>
+#include <mutex>
+
+#define VALIDATION_ERROR_MAP_IMPL
+
+#include "vk_loader_platform.h"
+#include "vk_dispatch_table_helper.h"
+#include "vk_layer_data.h"
+#include "vk_layer_extension_utils.h"
+#include "vk_layer_logging.h"
+#include "vk_extension_helper.h"
+#include "vk_layer_utils.h"
+
+class layer_chassis;
+
+std::vector<layer_chassis *> global_interceptor_list;
+debug_report_data *report_data = VK_NULL_HANDLE;
+
+#include "chassis.h"
+
+struct instance_layer_data {
+    VkLayerInstanceDispatchTable dispatch_table;
+    VkInstance instance = VK_NULL_HANDLE;
+    debug_report_data *report_data = nullptr;
+    std::vector<VkDebugReportCallbackEXT> logging_callback;
+    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
+    InstanceExtensions extensions;
+};
+
+struct layer_data {
+    debug_report_data *report_data = nullptr;
+    VkLayerDispatchTable dispatch_table;
+    DeviceExtensions extensions = {};
+    VkDevice device = VK_NULL_HANDLE;
+    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
+    instance_layer_data *instance_data = nullptr;
+};
+
+static std::unordered_map<void *, layer_data *> layer_data_map;
+static std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;
+
+#include "interceptor_objects.h"
+
+using mutex_t = std::mutex;
+using lock_guard_t = std::lock_guard<mutex_t>;
+using unique_lock_t = std::unique_lock<mutex_t>;
+
+namespace vulkan_layer_chassis {
+
+using std::unordered_map;
+
+static mutex_t global_lock;
+
+static const VkLayerProperties global_layer = {
+    "VK_LAYER_KHRONOS_validation", 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
+
+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);
+    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->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;
+    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) {
+    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);
+}
+
+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);
+
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+    return instance_data->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;
+
+    // Init dispatch array and call registration functions
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateCreateInstance(pCreateInfo, pAllocator, pInstance);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
+    }
+
+    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
+
+    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->extensions.InitFromInstanceCreateInfo((pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0), pCreateInfo);
+    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator, "lunarg_validation_layer");
+    report_data = instance_data->report_data;
+
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
+    }
+
+    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);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateDestroyInstance(instance, pAllocator);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordDestroyInstance(instance, pAllocator);
+    }
+
+    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
+
+    lock_guard_t lock(global_lock);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordDestroyInstance(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();
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordDestroyInstance(instance, pAllocator);
+    }
+    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 *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
+
+    unique_lock_t lock(global_lock);
+    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
+    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
+    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
+    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
+
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
+    }
+    lock.unlock();
+
+    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
+
+    lock.lock();
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
+    }
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
+    device_data->instance_data = instance_data;
+    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
+    device_data->device = *pDevice;
+    device_data->physical_device = gpu;
+    device_data->report_data = layer_debug_utils_create_device(instance_data->report_data, *pDevice);
+    VkPhysicalDeviceProperties physical_device_properties{};
+    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &physical_device_properties);
+    device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, physical_device_properties.apiVersion, pCreateInfo);
+    lock.unlock();
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(device);
+    layer_data *device_data = GetLayerDataPtr(key, layer_data_map);
+
+    unique_lock_t lock(global_lock);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateDestroyDevice(device, pAllocator);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordDestroyDevice(device, pAllocator);
+    }
+    layer_debug_utils_destroy_device(device);
+    lock.unlock();
+
+    device_data->dispatch_table.DestroyDevice(device, pAllocator);
+
+    lock.lock();
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordDestroyDevice(device, pAllocator);
+    }
+
+    FreeLayerDataPtr(key, layer_data_map);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
+                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkDebugReportCallbackEXT *pCallback) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
+    }
+    VkResult result = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
+    result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallValidateDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    }
+    for (auto intercept : global_interceptor_list) {
+        intercept->PreCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    }
+    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
+    for (auto intercept : global_interceptor_list) {
+        intercept->PostCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    }
+}
+"""
+
+    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)
+        # Multiple inclusion protection & C++ namespace.
+        self.header = False
+        if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
+            self.header = True
+            write('#pragma once', file=self.outFile)
+            self.newline()
+        # User-supplied prefix text, if any (list of strings)
+        if self.header:
+            if (genOpts.prefixText):
+                for s in genOpts.prefixText:
+                    write(s, file=self.outFile)
+            write('#include "vulkan/vk_layer.h"', file=self.outFile)
+            write('#include <unordered_map>\n', file=self.outFile)
+            write('class layer_chassis;', file=self.outFile)
+            write('extern std::vector<layer_chassis *> global_interceptor_list;', file=self.outFile)
+            write('extern debug_report_data *report_data;\n', file=self.outFile)
+            write('namespace vulkan_layer_chassis {\n', file=self.outFile)
+        else:
+            write(self.inline_custom_source_preamble, file=self.outFile)
+
+        # Initialize Enum Section
+        self.layer_factory += '// Layer Factory base class definition\n'
+        self.layer_factory += 'class layer_chassis {\n'
+        self.layer_factory += '    public:\n'
+        self.layer_factory += '        layer_chassis() {\n'
+        self.layer_factory += '            global_interceptor_list.emplace_back(this);\n'
+        self.layer_factory += '        };\n'
+        self.layer_factory += '\n'
+        self.layer_factory += '        std::string layer_name = "CHASSIS";\n'
+        self.layer_factory += '\n'
+        self.layer_factory += '        // Pre/post hook point declarations\n'
+    #
+    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 += '};\n'
+            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(";", " {};")
+
+        if 'GetPhysicalDeviceMemoryProperties' in prototype:
+            stop = 'here'
+
+        # 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
+        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.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
+                self.layer_factory += '#ifdef %s\n' % self.featureExtraProtect
+            # Update base class with virtual function declarations
+            self.layer_factory += self.BaseClassCdecl(cmdinfo.elem, name)
+            # Update function intercepts
+            self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
+            if (self.featureExtraProtect != None):
+                self.intercepts += [ '#endif' ]
+                self.layer_factory += '#endif\n'
+            return
+
+        manual_functions = [
+            # Include functions here to be interecpted w/ manually implemented function bodies
+            'vkGetDeviceProcAddr',
+            'vkGetInstanceProcAddr',
+            'vkGetPhysicalDeviceProcAddr',
+            'vkCreateDevice',
+            'vkDestroyDevice',
+            'vkCreateInstance',
+            'vkDestroyInstance',
+            'vkCreateDebugReportCallbackEXT',
+            'vkDestroyDebugReportCallbackEXT',
+            'vkEnumerateInstanceLayerProperties',
+            'vkEnumerateInstanceExtensionProperties',
+            'vkEnumerateDeviceLayerProperties',
+            'vkEnumerateDeviceExtensionProperties',
+        ]
+        if name in manual_functions:
+            self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
+            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'
+        map_name = 'layer_data'
+        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'
+            map_name = 'instance_layer_data'
+        self.appendSection('command', '    %s *%s_data = GetLayerDataPtr(get_dispatch_key(%s), %s_map);' % (map_name, device_or_instance, dispatchable_name, map_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','%s_data->dispatch_table.' % (device_or_instance),1)
+
+        # Declare result variable, if any.
+        return_map = {
+            'void': 'return;',
+            'VkResult': 'return VK_ERROR_VALIDATION_FAILED_EXT;',
+            'PFN_vkVoidFunction': 'return nullptr;',
+            'VkBool32': 'return VK_FALSE;',
+            }
+        resulttype = cmdinfo.elem.find('proto/type')
+        assignresult = ''
+        if (resulttype.text != 'void'):
+            assignresult = resulttype.text + ' result = '
+
+        # Set up skip and locking
+        self.appendSection('command', '    {')
+        self.appendSection('command', '        bool skip = false;')
+        self.appendSection('command', '        std::lock_guard<std::mutex> lock(global_lock);')
+
+        # Generate pre-call validation source code
+        self.appendSection('command', '        for (auto intercept : global_interceptor_list) {')
+        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', '        for (auto intercept : global_interceptor_list) {')
+        self.appendSection('command', '            intercept->PreCallRecord%s(%s);' % (api_function_name[2:], paramstext))
+        self.appendSection('command', '        }')
+        self.appendSection('command', '    }')
+
+        self.appendSection('command', '    ' + assignresult + API + '(' + paramstext + ');')
+
+        # Generate post-call object processing source code
+        self.appendSection('command', '    {')
+        self.appendSection('command', '        std::lock_guard<std::mutex> lock(global_lock);')
+        self.appendSection('command', '        for (auto intercept : global_interceptor_list) {')
+        self.appendSection('command', '            intercept->PostCallRecord%s(%s);' % (api_function_name[2:], paramstext))
+        self.appendSection('command', '        }')
+        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