Layers: Implement unique_objects layer using vk.xml
authorMark Lobodzinski <mark@lunarg.com>
Tue, 6 Sep 2016 22:12:23 +0000 (16:12 -0600)
committerMark Lobodzinski <mark@lunarg.com>
Thu, 6 Oct 2016 21:54:51 +0000 (15:54 -0600)
UniqueObjects was the final LVL layer not using vk.xml for codegen.
The new implementation follows the threading layer model which
(outside of safe_struct dependencies) is more tolerant of API
changes. Also updated for structure and style.

build-android/android-generate.bat - Updated for build
build-android/android-generate.sh  - Updated for build
generator.py                       - Added Unique Objects Generator
genvk.py                           - Added call to U_O generator
layers/CMakeLists.txt              - Updated for build
layers/unique_objects.cpp          - New: manually generated code
layers/unique_objects.h            - Now a true header file
vk-layer-generate.py               - killed!

Change-Id: I0d57871dfd2600829502f0bffd7cf6f926b7d5e7

build-android/android-generate.bat
build-android/android-generate.sh
generator.py
genvk.py
layers/CMakeLists.txt
layers/unique_objects.cpp [new file with mode: 0644]
layers/unique_objects.h
layers/vk_layer_logging.h
vk-layer-generate.py [deleted file]

index a70642e..8023742 100644 (file)
@@ -24,11 +24,10 @@ python ../vk-generate.py Android dispatch-table-ops layer > generated/include/vk
 python ../vk_helper.py --gen_enum_string_helper ../include/vulkan/vulkan.h --abs_out_dir generated/include\r
 python ../vk_helper.py --gen_struct_wrappers ../include/vulkan/vulkan.h --abs_out_dir generated/include\r
 \r
-python ../vk-layer-generate.py Android unique_objects ../include/vulkan/vulkan.h > generated/include/unique_objects.cpp\r
-\r
 cd generated/include\r
 python ../../../genvk.py threading -registry ../../../vk.xml thread_check.h\r
 python ../../../genvk.py paramchecker -registry ../../../vk.xml parameter_validation.h\r
+python ../../../genvk.py unique_objects -registry ../../../vk.xml unique_objects_wrappers.h\r
 cd ../..\r
 \r
 copy /Y ..\layers\vk_layer_config.cpp   generated\common\\r
@@ -51,10 +50,7 @@ for %%G in (core_validation image object_tracker parameter_validation swapchain
     copy ..\layers\%%G.cpp   generated\layer-src\%%G\r
     echo apply from: "../common.gradle"  > generated\gradle-build\%%G\build.gradle\r
 )\r
-copy generated\include\unique_objects.cpp generated\layer-src\unique_objects\r
 copy generated\common\descriptor_sets.cpp generated\layer-src\core_validation\descriptor_sets.cpp\r
 copy generated\include\vk_safe_struct.cpp generated\layer-src\core_validation\vk_safe_struct.cpp\r
 move generated\include\vk_safe_struct.cpp generated\layer-src\unique_objects\vk_safe_struct.cpp\r
 echo apply from: "../common.gradle"  > generated\gradle-build\unique_objects\build.gradle\r
-\r
-del  /f /q generated\include\unique_objects.cpp\r
index fb0e867..847828f 100755 (executable)
@@ -26,9 +26,9 @@ python ../vk-generate.py Android dispatch-table-ops layer > generated/include/vk
 python ../vk_helper.py --gen_enum_string_helper ../include/vulkan/vulkan.h --abs_out_dir generated/include
 python ../vk_helper.py --gen_struct_wrappers ../include/vulkan/vulkan.h --abs_out_dir generated/include
 
-python ../vk-layer-generate.py Android unique_objects ../include/vulkan/vulkan.h > generated/include/unique_objects.cpp
 ( cd generated/include; python ../../../genvk.py threading -registry ../../../vk.xml thread_check.h )
 ( cd generated/include; python ../../../genvk.py paramchecker -registry ../../../vk.xml parameter_validation.h )
+( cd generated/include; python ../../../genvk.py unique_objects -registry ../../../vk.xml unique_objects_wrappers.h )
 
 cp -f ../layers/vk_layer_config.cpp   generated/common/
 cp -f ../layers/vk_layer_extension_utils.cpp  generated/common/
@@ -40,7 +40,7 @@ cp -f ../layers/descriptor_sets.cpp   generated/common/
 # 1 to 1 correspondence -- one layer one source file; additional files are copied
 # at fixup step
 declare layers=(core_validation image object_tracker parameter_validation swapchain threading unique_objects)
-declare src_dirs=(../layers ../layers ../layers ../layers ../layers ../layers generated/include)
+declare src_dirs=(../layers ../layers ../layers ../layers ../layers ../layers ../layers)
 
 SRC_ROOT=generated/layer-src
 BUILD_ROOT=generated/gradle-build
@@ -63,7 +63,4 @@ cp  generated/common/descriptor_sets.cpp ${SRC_ROOT}/core_validation/descriptor_
 cp  generated/include/vk_safe_struct.cpp ${SRC_ROOT}/core_validation/vk_safe_struct.cpp
 mv  generated/include/vk_safe_struct.cpp ${SRC_ROOT}/unique_objects/vk_safe_struct.cpp
 
-# fixup - remove copied files from generated/include
-rm  generated/include/unique_objects.cpp
-
 exit 0
index a020d4d..c17a644 100755 (executable)
@@ -417,6 +417,80 @@ class ParamCheckerGeneratorOptions(GeneratorOptions):
         self.alignFuncParam  = alignFuncParam
         self.genDirectory    = genDirectory
 
+# 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):
+    """Represents options during C interface generation for headers"""
+    def __init__(self,
+                 filename = None,
+                 apiname = None,
+                 profile = None,
+                 versions = '.*',
+                 emitversions = '.*',
+                 defaultExtensions = None,
+                 addExtensions = None,
+                 removeExtensions = None,
+                 sortProcedure = regSortFeatures,
+                 prefixText = "",
+                 genFuncPointers = True,
+                 protectFile = False,
+                 protectFeature = True,
+                 protectProto = None,
+                 protectProtoStr = None,
+                 apicall = '',
+                 apientry = '',
+                 apientryp = '',
+                 indentFuncProto = True,
+                 indentFuncPointer = False,
+                 alignFuncParam = 0,
+                 genDirectory = None):
+        GeneratorOptions.__init__(self, filename, apiname, profile,
+                                  versions, emitversions, defaultExtensions,
+                                  addExtensions, removeExtensions, sortProcedure)
+        self.prefixText      = prefixText
+        self.genFuncPointers = genFuncPointers
+        self.protectFile     = protectFile
+        self.protectFeature  = protectFeature
+        self.protectProto    = protectProto
+        self.protectProtoStr = protectProtoStr
+        self.apicall         = apicall
+        self.apientry        = apientry
+        self.apientryp       = apientryp
+        self.indentFuncProto = indentFuncProto
+        self.indentFuncPointer = indentFuncPointer
+        self.alignFuncParam  = alignFuncParam
+        self.genDirectory    = genDirectory
 
 # OutputGenerator - base class for generating API interfaces.
 # Manages basic logic, logging, and output file control
@@ -3720,3 +3794,667 @@ class ParamCheckerOutputGenerator(OutputGenerator):
                 cmdDef += indent + 'return skipCall;\n'
                 cmdDef += '}\n'
                 self.appendSection('command', cmdDef)
+
+# 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
+        # Commands to ignore
+        self.intercepts = []
+        # Commands which are not autogenerated but still intercepted
+        self.no_autogen_list = [
+            'vkGetDeviceProcAddr', 
+            'vkGetInstanceProcAddr',
+            'vkCreateInstance',
+            'vkDestroyInstance',
+            'vkCreateDevice',
+            'vkDestroyDevice',
+            'vkAllocateMemory',
+            'vkCreateComputePipelines',
+            'vkCreateGraphicsPipelines',
+            'vkCreateSwapchainKHR',
+            'vkGetSwapchainImagesKHR',
+            'vkEnumerateInstanceLayerProperties',
+            'vkEnumerateDeviceLayerProperties',
+            'vkEnumerateInstanceExtensionProperties',
+            ]
+        # Commands shadowed by interface functions and are not implemented
+        self.interface_functions = [
+            'vkGetPhysicalDeviceDisplayPropertiesKHR',
+            'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
+            'vkGetDisplayPlaneSupportedDisplaysKHR',
+            'vkGetDisplayModePropertiesKHR',
+            # DebugReport APIs are hooked, but handled separately in the source file
+            '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.structNames = []                             # List of Vulkan struct typenames
+        self.structTypes = dict()                         # Map of Vulkan struct typename to required VkStructureType
+        self.handleTypes = set()                          # Set of handle type names
+        self.commands = []                                # List of CommandData records for all Vulkan commands
+        self.structMembers = []                           # List of StructMemberData records for all Vulkan structs
+        self.flags = set()                                # Map of flags typenames
+        # Named tuples to store struct and command data
+        self.StructType = namedtuple('StructType', ['name', 'value'])
+        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy'])
+        self.CommandData = namedtuple('CommandData', ['name', 'return_type', 'params', 'cdecl'])
+        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)
+    #
+    def endFile(self):
+        self.newline()
+        # Record intercepted procedures
+        write('// intercepts', file=self.outFile)
+        write('struct { const char* name; PFN_vkVoidFunction pFunc;} procmap[] = {', 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)
+        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):
+        # Start processing in superclass
+        OutputGenerator.beginFeature(self, interface, emit)
+        self.headerVersion = None
+        self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+        self.structNames = []
+        self.structTypes = dict()
+        self.handleTypes = set()
+        self.commands = []
+        self.structMembers = []
+        self.cmdMembers = []
+        self.flags = set()
+        self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
+        self.CmdMemberData = namedtuple('CmdMemberData', ['name', 'members'])
+    #
+    def endFeature(self):
+        # 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']):
+                if (self.genOpts.protectProto):
+                    write(self.genOpts.protectProto,
+                          self.genOpts.protectProtoStr, file=self.outFile)
+                write('\n'.join(self.sections['command']), end='', file=self.outFile)
+            if (self.featureExtraProtect != None):
+                write('\n#endif //', self.featureExtraProtect, file=self.outFile)
+            else:
+                self.newline()
+        # Finish processing in superclass
+        OutputGenerator.endFeature(self)
+    #
+    def genType(self, typeinfo, name):
+        OutputGenerator.genType(self, typeinfo, name)
+        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.structNames.append(name)
+            self.genStruct(typeinfo, name)
+    #
+    # 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.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.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):
+        OutputGenerator.genStruct(self, typeinfo, typeName)
+        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
+            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=member.attrib.get('validextensionstructs') if name == 'pNext' else None,
+                                                 cdecl=cdecl,
+                                                 islocal=False,
+                                                 iscreate=False,
+                                                 isdestroy=False))
+        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
+    #
+    # Generate source for creating a non-dispatchable object
+    def generate_create_ndo_code(self, indent, proto, params, cmd_info):
+        create_ndo_code = ''
+        if True in [create_txt in proto.text for create_txt in ['Create', 'Allocate']]:
+            handle_type = params[-1].find('type')
+            if self.isHandleTypeNonDispatchable(handle_type.text):
+                # Check for special case where multiple handles are returned
+                ndo_array = False
+                if cmd_info[-1].len is not None:
+                    ndo_array = True;
+                handle_name = params[-1].find('name')
+                create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent)
+                indent = self.incIndent(indent)
+                create_ndo_code += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
+                ndo_dest = '*%s' % handle_name.text
+                if ndo_array == True:
+                    create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len)
+                    indent = self.incIndent(indent)
+                    ndo_dest = '%s[index0]' % cmd_info[-1].name
+                create_ndo_code += '%suint64_t unique_id = global_unique_id++;\n' % (indent)
+                create_ndo_code += '%sdev_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(%s);\n' % (indent, ndo_dest)
+                create_ndo_code += '%s%s = reinterpret_cast<%s&>(unique_id);\n' % (indent, ndo_dest, handle_type.text)
+                if ndo_array == True:
+                    indent = self.decIndent(indent)
+                    create_ndo_code += '%s}\n' % indent
+                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 += '%sdev_data->unique_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)dev_data->unique_id_mapping[%s_id];\n' % (indent, cmd_info[param].name, cmd_info[param].type, cmd_info[param].name)
+                    destroy_ndo_code += '%sdev_data->unique_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):
+        cleanup = '%sif (local_%s%s)\n' % (indent, prefix, name)
+        if len is not None:
+            cleanup += '%s    delete[] local_%s%s;\n' % (indent, prefix, name)
+        else:
+            cleanup += '%s    delete local_%s%s;\n' % (indent, prefix, name)
+        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] = (%s)dev_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(%s[%s])];\n' % (indent, prefix, ndo_name, index, ndo_type, 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] = (%s)dev_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(%s%s[%s])];\n' % (indent, prefix, ndo_name, index, ndo_type, 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):       #### LUGMAL This line needs to be skipped for destroy_ndo and not destroy_array
+                    pre_call_code += '%s    %s = (%s)dev_data->unique_id_mapping[reinterpret_cast<uint64_t &>(%s)];\n' % (indent, ndo_name, ndo_type, 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 = (%s)dev_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(%s%s)];\n' % (indent, prefix, ndo_name, ndo_type, 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 = ''
+        struct_member_dict = dict(self.structMembers)
+        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:
+            # 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):
+                    (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 struct_member_dict:
+                # All structs at first level will have an NDO
+                if self.struct_contains_ndo(member.type) == True:
+                    struct_info = struct_member_dict[member.type]
+                    # 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)
+                        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)
+                    # Single Struct
+                    else:
+                        # 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
+                        indent = self.decIndent(indent)
+                        pre_code += '%s    }\n' % indent
+                        if first_level_param == True:
+                            post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len)
+        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):
+        if cmdname in self.interface_functions:
+            return
+        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", reinterpret_cast<PFN_vkVoidFunction>(%s)},' % (cmdname,cmdname[2:]) ]
+            return
+        # Add struct-member type information to command parameter information
+        OutputGenerator.genCmd(self, cmdinfo, cmdname)
+        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']] else False
+
+            membersInfo.append(self.CommandParam(type=type,
+                                                 name=name,
+                                                 ispointer=ispointer,
+                                                 isconst=isconst,
+                                                 iscount=iscount,
+                                                 len=len,
+                                                 extstructs=member.attrib.get('validextensionstructs') if name == 'pNext' else None,
+                                                 cdecl=cdecl,
+                                                 islocal=islocal,
+                                                 iscreate=iscreate,
+                                                 isdestroy=isdestroy))
+        self.cmdMembers.append(self.CmdMemberData(name=cmdname, members=membersInfo))
+        # 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:
+            return
+        # Record that the function will be intercepted
+        if (self.featureExtraProtect != None):
+            self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
+        self.intercepts += [ '    {"%s", reinterpret_cast<PFN_vkVoidFunction>(%s)},' % (cmdname,cmdname[2:]) ]
+        if (self.featureExtraProtect != None):
+            self.intercepts += [ '#endif' ]
+        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
+        self.appendSection('command', '    layer_data *dev_data = get_my_data_ptr(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
+        cmd_member_dict = dict(self.cmdMembers)
+        params = cmd_member_dict[cmdname]
+        for param in params:
+            if param.islocal == True:
+                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
+        if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]:
+            API = cmdinfo.elem.attrib.get('name').replace('vk','dev_data->instance_dispatch_table->',1)
+        else:
+            API = cmdinfo.elem.attrib.get('name').replace('vk','dev_data->device_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', '}')
index 993477c..c34c8a4 100755 (executable)
--- a/genvk.py
+++ b/genvk.py
@@ -18,6 +18,7 @@ import sys, time, pdb, string, cProfile
 from reg import *
 from generator import write, CGeneratorOptions, COutputGenerator, DocGeneratorOptions, DocOutputGenerator, PyOutputGenerator, ValidityOutputGenerator, HostSynchronizationOutputGenerator, ThreadGeneratorOptions, ThreadOutputGenerator
 from generator import ParamCheckerGeneratorOptions, ParamCheckerOutputGenerator
+from generator import UniqueObjectsGeneratorOptions, UniqueObjectsOutputGenerator
 
 # debug - start header generation in debugger
 # dump - dump registry after loading
@@ -308,6 +309,28 @@ buildList = [
         alignFuncParam    = 48,
         genDirectory      = outDir)
     ],
+    [ UniqueObjectsOutputGenerator,
+      UniqueObjectsGeneratorOptions(
+        filename          = 'unique_objects_wrappers.h',
+        apiname           = 'vulkan',
+        profile           = None,
+        versions          = allVersions,
+        emitversions      = allVersions,
+        defaultExtensions = 'vulkan',
+        addExtensions     = None,
+        removeExtensions  = None,
+        prefixText        = prefixStrings + vkPrefixStrings,
+        genFuncPointers   = True,
+        protectFile       = False,
+        protectFeature    = False,
+        protectProto      = None,
+        protectProtoStr   = 'VK_NO_PROTOTYPES',
+        apicall           = 'VKAPI_ATTR ',
+        apientry          = 'VKAPI_CALL ',
+        apientryp         = 'VKAPI_PTR *',
+        alignFuncParam    = 48,
+        genDirectory      = outDir)
+    ],
     None
 ]
 
index 8a84fa2..0ccfc87 100644 (file)
@@ -7,13 +7,6 @@ macro(run_vk_helper subcmd)
     )
 endmacro()
 
-macro(run_vk_layer_generate subcmd output)
-    add_custom_command(OUTPUT ${output}
-        COMMAND ${PYTHON_CMD} ${PROJECT_SOURCE_DIR}/vk-layer-generate.py ${DisplayServer} ${subcmd} ${PROJECT_SOURCE_DIR}/include/vulkan/vulkan.h > ${output}
-        DEPENDS ${PROJECT_SOURCE_DIR}/vk-layer-generate.py ${PROJECT_SOURCE_DIR}/include/vulkan/vulkan.h ${PROJECT_SOURCE_DIR}/vulkan.py
-    )
-endmacro()
-
 macro(run_vk_layer_xml_generate subcmd output)
     add_custom_command(OUTPUT ${output}
         COMMAND ${PYTHON_CMD} ${PROJECT_SOURCE_DIR}/genvk.py -registry ${PROJECT_SOURCE_DIR}/vk.xml ${output}
@@ -181,8 +174,8 @@ add_custom_target(generate_vk_layer_helpers DEPENDS
 )
 
 run_vk_layer_xml_generate(Threading thread_check.h)
-run_vk_layer_generate(unique_objects unique_objects.cpp)
 run_vk_layer_xml_generate(ParamChecker parameter_validation.h)
+run_vk_layer_xml_generate(UniqueObjects unique_objects_wrappers.h)
 
 # Layer Utils Library
 # For Windows, we use a static lib because the Windows loader has a fairly restrictive loader search
@@ -200,7 +193,7 @@ add_vk_layer(image image.cpp vk_layer_table.cpp)
 add_vk_layer(swapchain swapchain.cpp vk_layer_table.cpp)
 # generated
 add_vk_layer(threading threading.cpp thread_check.h vk_layer_table.cpp)
-add_vk_layer(unique_objects unique_objects.cpp vk_layer_table.cpp vk_safe_struct.cpp)
+add_vk_layer(unique_objects unique_objects.cpp unique_objects_wrappers.h vk_layer_table.cpp vk_safe_struct.cpp)
 add_vk_layer(parameter_validation parameter_validation.cpp parameter_validation.h vk_layer_table.cpp)
 
 # Core validation has additional dependencies
diff --git a/layers/unique_objects.cpp b/layers/unique_objects.cpp
new file mode 100644 (file)
index 0000000..b23f774
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unordered_map>
+#include <vector>
+#include <list>
+#include <memory>
+
+#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_table.h"
+#include "vk_layer_logging.h"
+#include "unique_objects.h"
+#include "vk_dispatch_table_helper.h"
+#include "vk_struct_string_helper_cpp.h"
+#include "vk_layer_data.h"
+#include "vk_layer_utils.h"
+
+#include "unique_objects_wrappers.h"
+
+namespace unique_objects {
+
+static void initUniqueObjects(layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
+    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "google_unique_objects");
+}
+
+// Handle CreateInstance Extensions
+static void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
+    uint32_t i;
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkLayerInstanceDispatchTable *disp_table = instance_data->instance_dispatch_table;
+    instance_ext_map[disp_table] = {};
+
+    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].wsi_enabled = true;
+        }
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].display_enabled = true;
+        }
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].xlib_enabled = true;
+        }
+#endif
+#ifdef VK_USE_PLATFORM_XCB_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].xcb_enabled = true;
+        }
+#endif
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].wayland_enabled = true;
+        }
+#endif
+#ifdef VK_USE_PLATFORM_MIR_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].mir_enabled = true;
+        }
+#endif
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].android_enabled = true;
+        }
+#endif
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) {
+            instance_ext_map[disp_table].win32_enabled = true;
+        }
+#endif
+
+        // Check for recognized instance extensions
+        layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kUniqueObjectsSupportedInstanceExtensions)) {
+            log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                    0, "UniqueObjects",
+                    "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]);
+        }
+    }
+}
+
+// Handle CreateDevice Extensions
+static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkLayerDispatchTable *disp_table = device_data->device_dispatch_table;
+    PFN_vkGetDeviceProcAddr gpa = disp_table->GetDeviceProcAddr;
+
+    device_data->device_dispatch_table->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
+    disp_table->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
+    disp_table->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
+    disp_table->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
+    disp_table->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
+    device_data->wsi_enabled = false;
+
+    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
+            device_data->wsi_enabled = true;
+        }
+        // Check for recognized device extensions
+        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kUniqueObjectsSupportedDeviceExtensions)) {
+            log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                    0, "UniqueObjects",
+                    "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;
+    }
+
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
+    instance_data->instance = *pInstance;
+    instance_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
+    layer_init_instance_dispatch_table(*pInstance, instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
+
+    instance_data->instance = *pInstance;
+    instance_data->report_data =
+        debug_report_create_instance(instance_data->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
+                                     pCreateInfo->ppEnabledExtensionNames);
+
+    // Set up temporary debug callbacks to output messages at CreateInstance-time
+    if (!layer_copy_tmp_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_callbacks, &instance_data->tmp_dbg_create_infos,
+                                  &instance_data->tmp_callbacks)) {
+        if (instance_data->num_tmp_callbacks > 0) {
+            if (layer_enable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks,
+                                           instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks)) {
+                layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
+                instance_data->num_tmp_callbacks = 0;
+            }
+        }
+    }
+
+    initUniqueObjects(instance_data, pAllocator);
+    checkInstanceRegisterExtensions(pCreateInfo, *pInstance);
+
+    // Disable and free tmp callbacks, no longer necessary
+    if (instance_data->num_tmp_callbacks > 0) {
+        layer_disable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks, instance_data->tmp_callbacks);
+        layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
+        instance_data->num_tmp_callbacks = 0;
+    }
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(instance);
+    layer_data *instance_data = get_my_data_ptr(key, layer_data_map);
+    VkLayerInstanceDispatchTable *disp_table = instance_data->instance_dispatch_table;
+    instance_ext_map.erase(disp_table);
+    disp_table->DestroyInstance(instance, pAllocator);
+
+    // Clean up logging callback, if any
+    while (instance_data->logging_callback.size() > 0) {
+        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
+        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
+        instance_data->logging_callback.pop_back();
+    }
+
+    layer_debug_report_destroy_instance(instance_data->report_data);
+    layer_data_map.erase(key);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
+                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
+    layer_data *my_instance_data = get_my_data_ptr(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 = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
+    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
+
+    // Setup layer's device dispatch table
+    my_device_data->device_dispatch_table = new VkLayerDispatchTable;
+    layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
+
+    createDeviceRegisterExtensions(pCreateInfo, *pDevice);
+    // Set gpu for this device in order to get at any objects mapped at instance level
+
+    my_device_data->gpu = gpu;
+
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(device);
+    layer_data *dev_data = get_my_data_ptr(key, layer_data_map);
+
+    layer_debug_report_destroy_device(device);
+    dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
+    layer_data_map.erase(key);
+}
+
+static const VkLayerProperties globalLayerProps = {"VK_LAYER_GOOGLE_unique_objects",
+                                                   VK_LAYER_API_VERSION, // specVersion
+                                                   1,                    // implementationVersion
+                                                   "Google Validation Layer"};
+
+static inline PFN_vkVoidFunction layer_intercept_proc(const char *name) {
+    for (int i = 0; i < sizeof(procmap) / sizeof(procmap[0]); i++) {
+        if (!strcmp(name, procmap[i].name))
+            return procmap[i].pFunc;
+    }
+    return NULL;
+}
+
+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);
+    layer_data *instance_data = get_my_data_ptr(key, layer_data_map);
+    return instance_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
+    PFN_vkVoidFunction addr;
+    assert(device);
+    addr = layer_intercept_proc(funcName);
+    if (addr) {
+        return addr;
+    }
+
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkLayerDispatchTable *disp_table = dev_data->device_dispatch_table;
+    if (disp_table->GetDeviceProcAddr == NULL) {
+        return NULL;
+    }
+    return disp_table->GetDeviceProcAddr(device, funcName);
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
+    PFN_vkVoidFunction addr;
+
+    addr = layer_intercept_proc(funcName);
+    if (addr) {
+        return addr;
+    }
+    assert(instance);
+
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    addr = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
+    if (addr) {
+        return addr;
+    }
+
+    VkLayerInstanceDispatchTable *disp_table = instance_data->instance_dispatch_table;
+    if (disp_table->GetInstanceProcAddr == NULL) {
+        return NULL;
+    }
+    return disp_table->GetInstanceProcAddr(instance, funcName);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
+                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
+    const VkMemoryAllocateInfo *input_allocate_info = pAllocateInfo;
+    std::unique_ptr<safe_VkMemoryAllocateInfo> safe_allocate_info;
+    layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+    if ((pAllocateInfo != nullptr) &&
+        ContainsExtStruct(pAllocateInfo, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV)) {
+        std::unique_ptr<safe_VkDedicatedAllocationMemoryAllocateInfoNV> safe_dedicated_allocate_info;
+        // Assuming there is only one extension struct of this type in the list for now
+        safe_dedicated_allocate_info =
+            std::unique_ptr<safe_VkDedicatedAllocationMemoryAllocateInfoNV>(new safe_VkDedicatedAllocationMemoryAllocateInfoNV);
+        safe_allocate_info = std::unique_ptr<safe_VkMemoryAllocateInfo>(new safe_VkMemoryAllocateInfo(pAllocateInfo));
+        input_allocate_info = reinterpret_cast<const VkMemoryAllocateInfo *>(safe_allocate_info.get());
+
+        const GenericHeader *orig_pnext = reinterpret_cast<const GenericHeader *>(pAllocateInfo->pNext);
+        GenericHeader *input_pnext = reinterpret_cast<GenericHeader *>(safe_allocate_info.get());
+        while (orig_pnext != nullptr) {
+            if (orig_pnext->sType == VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV) {
+                safe_dedicated_allocate_info->initialize(
+                    reinterpret_cast<const VkDedicatedAllocationMemoryAllocateInfoNV *>(orig_pnext));
+
+                std::unique_lock<std::mutex> lock(global_lock);
+
+                if (safe_dedicated_allocate_info->buffer != VK_NULL_HANDLE) {
+                    uint64_t local_buffer = reinterpret_cast<uint64_t &>(safe_dedicated_allocate_info->buffer);
+                    safe_dedicated_allocate_info->buffer =
+                        reinterpret_cast<VkBuffer &>(device_data->unique_id_mapping[local_buffer]);
+                }
+
+                if (safe_dedicated_allocate_info->image != VK_NULL_HANDLE) {
+                    uint64_t local_image = reinterpret_cast<uint64_t &>(safe_dedicated_allocate_info->image);
+                    safe_dedicated_allocate_info->image = reinterpret_cast<VkImage &>(device_data->unique_id_mapping[local_image]);
+                }
+
+                lock.unlock();
+
+                input_pnext->pNext = reinterpret_cast<GenericHeader *>(safe_dedicated_allocate_info.get());
+                input_pnext = reinterpret_cast<GenericHeader *>(input_pnext->pNext);
+            } else {
+                // TODO: generic handling of pNext copies
+            }
+
+            orig_pnext = reinterpret_cast<const GenericHeader *>(orig_pnext->pNext);
+        }
+    }
+
+    VkResult result = device_data->device_dispatch_table->AllocateMemory(device, input_allocate_info, pAllocator, pMemory);
+
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        uint64_t unique_id = global_unique_id++;
+        device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*pMemory);
+        *pMemory = reinterpret_cast<VkDeviceMemory &>(unique_id);
+    }
+
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
+                                                      const VkComputePipelineCreateInfo *pCreateInfos,
+                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
+    layer_data *my_device_data = get_my_data_ptr(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 =
+                    (VkPipeline)my_device_data
+                        ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)];
+            }
+            if (pCreateInfos[idx0].layout) {
+                local_pCreateInfos[idx0].layout =
+                    (VkPipelineLayout)
+                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].layout)];
+            }
+            if (pCreateInfos[idx0].stage.module) {
+                local_pCreateInfos[idx0].stage.module =
+                    (VkShaderModule)
+                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].stage.module)];
+            }
+        }
+    }
+    if (pipelineCache) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)];
+    }
+
+    VkResult result = my_device_data->device_dispatch_table->CreateComputePipelines(
+        device, pipelineCache, createInfoCount, (const VkComputePipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines);
+    delete[] local_pCreateInfos;
+    if (VK_SUCCESS == result) {
+        uint64_t unique_id = 0;
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t i = 0; i < createInfoCount; ++i) {
+            unique_id = global_unique_id++;
+            my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]);
+            pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id);
+        }
+    }
+    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 *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = NULL;
+    if (pCreateInfos) {
+        local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount];
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
+            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]);
+            if (pCreateInfos[idx0].basePipelineHandle) {
+                local_pCreateInfos[idx0].basePipelineHandle =
+                    (VkPipeline)my_device_data
+                        ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)];
+            }
+            if (pCreateInfos[idx0].layout) {
+                local_pCreateInfos[idx0].layout =
+                    (VkPipelineLayout)
+                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(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 =
+                            (VkShaderModule)my_device_data
+                                ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].pStages[idx1].module)];
+                    }
+                }
+            }
+            if (pCreateInfos[idx0].renderPass) {
+                local_pCreateInfos[idx0].renderPass =
+                    (VkRenderPass)
+                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].renderPass)];
+            }
+        }
+    }
+    if (pipelineCache) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)];
+    }
+
+    VkResult result = my_device_data->device_dispatch_table->CreateGraphicsPipelines(
+        device, pipelineCache, createInfoCount, (const VkGraphicsPipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines);
+    delete[] local_pCreateInfos;
+    if (VK_SUCCESS == result) {
+        uint64_t unique_id = 0;
+        std::lock_guard<std::mutex> lock(global_lock);
+        for (uint32_t i = 0; i < createInfoCount; ++i) {
+            unique_id = global_unique_id++;
+            my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]);
+            pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id);
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
+                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkDebugReportCallbackEXT *pMsgCallback) {
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    VkResult result =
+        instance_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
+
+    if (VK_SUCCESS == result) {
+        result = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    instance_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+    layer_destroy_msg_callback(instance_data->report_data, callback, 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) {
+    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
+    instance_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
+                                                                  pMsg);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
+    layer_data *my_map_data = get_my_data_ptr(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 =
+            (VkSwapchainKHR)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->oldSwapchain)];
+        // Need to pull surface mapping from the instance-level map
+        layer_data *instance_data = get_my_data_ptr(get_dispatch_key(my_map_data->gpu), layer_data_map);
+        local_pCreateInfo->surface =
+            (VkSurfaceKHR)instance_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->surface)];
+    }
+
+    VkResult result = my_map_data->device_dispatch_table->CreateSwapchainKHR(
+        device, (const VkSwapchainCreateInfoKHR *)local_pCreateInfo, pAllocator, pSwapchain);
+    if (local_pCreateInfo) {
+        delete local_pCreateInfo;
+    }
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        uint64_t unique_id = global_unique_id++;
+        my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*pSwapchain);
+        *pSwapchain = reinterpret_cast<VkSwapchainKHR &>(unique_id);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+                                                     VkImage *pSwapchainImages) {
+    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    if (VK_NULL_HANDLE != swapchain) {
+        std::lock_guard<std::mutex> lock(global_lock);
+        swapchain = (VkSwapchainKHR)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(swapchain)];
+    }
+    VkResult result =
+        my_device_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+    // TODO : Need to add corresponding code to delete these images
+    if (VK_SUCCESS == result) {
+        if ((*pSwapchainImageCount > 0) && pSwapchainImages) {
+            uint64_t unique_id = 0;
+            std::lock_guard<std::mutex> lock(global_lock);
+            for (uint32_t i = 0; i < *pSwapchainImageCount; ++i) {
+                unique_id = global_unique_id++;
+                my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pSwapchainImages[i]);
+                pSwapchainImages[i] = reinterpret_cast<VkImage &>(unique_id);
+            }
+        }
+    }
+    return result;
+}
+
+#ifndef __ANDROID__
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+                                                                     VkDisplayPropertiesKHR *pProperties) {
+    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
+    safe_VkDisplayPropertiesKHR *local_pProperties = NULL;
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        if (pProperties) {
+            local_pProperties = new safe_VkDisplayPropertiesKHR[*pPropertyCount];
+            for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+                local_pProperties[idx0].initialize(&pProperties[idx0]);
+                if (pProperties[idx0].display) {
+                    local_pProperties[idx0].display =
+                        (VkDisplayKHR)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pProperties[idx0].display)];
+                }
+            }
+        }
+    }
+
+    VkResult result = my_map_data->instance_dispatch_table->GetPhysicalDeviceDisplayPropertiesKHR(
+        physicalDevice, pPropertyCount, (VkDisplayPropertiesKHR *)local_pProperties);
+    if (result == VK_SUCCESS && pProperties) {
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            std::lock_guard<std::mutex> lock(global_lock);
+
+            uint64_t unique_id = global_unique_id++;
+            my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(local_pProperties[idx0].display);
+            pProperties[idx0].display = reinterpret_cast<VkDisplayKHR &>(unique_id);
+            pProperties[idx0].displayName = local_pProperties[idx0].displayName;
+            pProperties[idx0].physicalDimensions = local_pProperties[idx0].physicalDimensions;
+            pProperties[idx0].physicalResolution = local_pProperties[idx0].physicalResolution;
+            pProperties[idx0].supportedTransforms = local_pProperties[idx0].supportedTransforms;
+            pProperties[idx0].planeReorderPossible = local_pProperties[idx0].planeReorderPossible;
+            pProperties[idx0].persistentContent = local_pProperties[idx0].persistentContent;
+        }
+    }
+    if (local_pProperties) {
+        delete[] local_pProperties;
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+                                                                   uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
+    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
+    VkResult result = my_map_data->instance_dispatch_table->GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex,
+                                                                                                pDisplayCount, pDisplays);
+    if (VK_SUCCESS == result) {
+        if ((*pDisplayCount > 0) && pDisplays) {
+            std::lock_guard<std::mutex> lock(global_lock);
+            for (uint32_t i = 0; i < *pDisplayCount; i++) {
+                auto it = my_map_data->unique_id_mapping.find(reinterpret_cast<const uint64_t &>(pDisplays[i]));
+                assert(it != my_map_data->unique_id_mapping.end());
+                pDisplays[i] = reinterpret_cast<VkDisplayKHR &>(it->second);
+            }
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display,
+                                                           uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties) {
+    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
+    safe_VkDisplayModePropertiesKHR *local_pProperties = NULL;
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        display = (VkDisplayKHR)my_map_data->unique_id_mapping[reinterpret_cast<uint64_t &>(display)];
+        if (pProperties) {
+            local_pProperties = new safe_VkDisplayModePropertiesKHR[*pPropertyCount];
+            for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+                local_pProperties[idx0].initialize(&pProperties[idx0]);
+            }
+        }
+    }
+
+    VkResult result = my_map_data->instance_dispatch_table->GetDisplayModePropertiesKHR(
+        physicalDevice, display, pPropertyCount, (VkDisplayModePropertiesKHR *)local_pProperties);
+    if (result == VK_SUCCESS && pProperties) {
+        for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) {
+            std::lock_guard<std::mutex> lock(global_lock);
+
+            uint64_t unique_id = global_unique_id++;
+            my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(local_pProperties[idx0].displayMode);
+            pProperties[idx0].displayMode = reinterpret_cast<VkDisplayModeKHR &>(unique_id);
+            pProperties[idx0].parameters.visibleRegion.width = local_pProperties[idx0].parameters.visibleRegion.width;
+            pProperties[idx0].parameters.visibleRegion.height = local_pProperties[idx0].parameters.visibleRegion.height;
+            pProperties[idx0].parameters.refreshRate = local_pProperties[idx0].parameters.refreshRate;
+        }
+    }
+    if (local_pProperties) {
+        delete[] local_pProperties;
+    }
+    return result;
+}
+#endif
+
+} // namespace unique_objects
+
+// vk_layer_logging.h expects these to be defined
+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);
+}
index c597b6c..a0fe99e 100644 (file)
  * limitations under the License.
  *
  * Author: Tobin Ehlis <tobine@google.com>
- *         Mark Lobodzinski <mark@lunarg.com>
+ * Author: Mark Lobodzinski <mark@lunarg.com>
  */
 
-#include "vk_loader_platform.h"
 #include "vulkan/vulkan.h"
 
-#include <cinttypes>
-#include <memory>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <unordered_map>
-#include <vector>
-#include <mutex>
-
-#include "vulkan/vk_layer.h"
-#include "vk_layer_config.h"
-#include "vk_layer_table.h"
 #include "vk_layer_data.h"
-#include "vk_layer_logging.h"
-#include "vk_layer_extension_utils.h"
 #include "vk_safe_struct.h"
 #include "vk_layer_utils.h"
+#include "mutex"
+
+#pragma once
 
 namespace unique_objects {
 
@@ -101,6 +88,8 @@ struct layer_data {
 
     debug_report_data *report_data;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
+    VkLayerDispatchTable *device_dispatch_table;
+    VkLayerInstanceDispatchTable *instance_dispatch_table;
 
     // The following are for keeping track of the temporary callbacks that can
     // be used in vkCreateInstance and vkDestroyInstance:
@@ -126,10 +115,9 @@ struct instance_extension_enables {
     bool display_enabled;
 };
 
-static std::unordered_map<void *, struct instance_extension_enables> instanceExtMap;
+static std::unordered_map<void *, struct instance_extension_enables> instance_ext_map;
 static std::unordered_map<void *, layer_data *> layer_data_map;
-static device_table_map unique_objects_device_table_map;
-static instance_table_map unique_objects_instance_table_map;
+
 static std::mutex global_lock; // Protect map accesses and unique_id increments
 
 struct GenericHeader {
@@ -153,519 +141,4 @@ template <typename T> bool ContainsExtStruct(const T *target, VkStructureType ex
     return false;
 }
 
-static void init_unique_objects(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "google_unique_objects");
-}
-
-// Handle CreateInstance
-static void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
-    uint32_t i;
-    VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(unique_objects_instance_table_map, instance);
-
-    instanceExtMap[pDisp] = {};
-
-    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].wsi_enabled = true;
-        }
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].display_enabled = true;
-        }
-#ifdef VK_USE_PLATFORM_XLIB_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].xlib_enabled = true;
-        }
-#endif
-#ifdef VK_USE_PLATFORM_XCB_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].xcb_enabled = true;
-        }
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].wayland_enabled = true;
-        }
-#endif
-#ifdef VK_USE_PLATFORM_MIR_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].mir_enabled = true;
-        }
-#endif
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].android_enabled = true;
-        }
-#endif
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) {
-            instanceExtMap[pDisp].win32_enabled = true;
-        }
-#endif
-
-        // Check for recognized instance extensions
-        layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
-        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kUniqueObjectsSupportedInstanceExtensions)) {
-            log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                    0, "UniqueObjects",
-                    "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]);
-        }
-    }
-}
-
-VkResult explicit_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 = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
-    my_data->instance = *pInstance;
-    VkLayerInstanceDispatchTable *pTable = initInstanceTable(*pInstance, fpGetInstanceProcAddr, unique_objects_instance_table_map);
-
-    my_data->instance = *pInstance;
-    my_data->report_data = debug_report_create_instance(pTable, *pInstance, pCreateInfo->enabledExtensionCount,
-        pCreateInfo->ppEnabledExtensionNames);
-
-    // Set up temporary debug callbacks to output messages at CreateInstance-time
-    if (!layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_data->num_tmp_callbacks, &my_data->tmp_dbg_create_infos,
-                                  &my_data->tmp_callbacks)) {
-        if (my_data->num_tmp_callbacks > 0) {
-            if (layer_enable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_dbg_create_infos,
-                                           my_data->tmp_callbacks)) {
-                layer_free_tmp_callbacks(my_data->tmp_dbg_create_infos, my_data->tmp_callbacks);
-                my_data->num_tmp_callbacks = 0;
-            }
-        }
-    }
-
-    init_unique_objects(my_data, pAllocator);
-    checkInstanceRegisterExtensions(pCreateInfo, *pInstance);
-
-    // Disable and free tmp callbacks, no longer necessary
-    if (my_data->num_tmp_callbacks > 0) {
-        layer_disable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_callbacks);
-        layer_free_tmp_callbacks(my_data->tmp_dbg_create_infos, my_data->tmp_callbacks);
-        my_data->num_tmp_callbacks = 0;
-    }
-
-    return result;
-}
-
-void explicit_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(instance);
-    layer_data *my_data = get_my_data_ptr(key, layer_data_map);
-    VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(unique_objects_instance_table_map, instance);
-    instanceExtMap.erase(pDisp);
-    pDisp->DestroyInstance(instance, pAllocator);
-
-    // Clean up logging callback, if any
-    while (my_data->logging_callback.size() > 0) {
-        VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
-        layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
-        my_data->logging_callback.pop_back();
-    }
-
-    layer_debug_report_destroy_instance(my_data->report_data);
-    layer_data_map.erase(key);
-}
-
-// Handle CreateDevice
-static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
-    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    my_device_data->wsi_enabled = false;
-
-    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
-            my_device_data->wsi_enabled = true;
-        }
-        // Check for recognized device extensions
-        if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kUniqueObjectsSupportedDeviceExtensions)) {
-            log_msg(my_device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
-                    __LINE__, 0, "UniqueObjects",
-                    "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]);
-        }
-    }
-}
-
-VkResult explicit_CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
-                               VkDevice *pDevice) {
-    layer_data *my_instance_data = get_my_data_ptr(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 = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
-    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
-
-    // Setup layer's device dispatch table
-    initDeviceTable(*pDevice, fpGetDeviceProcAddr, unique_objects_device_table_map);
-
-    createDeviceRegisterExtensions(pCreateInfo, *pDevice);
-    // Set gpu for this device in order to get at any objects mapped at instance level
-
-    my_device_data->gpu = gpu;
-
-    return result;
-}
-
-void explicit_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
-    dispatch_key key = get_dispatch_key(device);
-    layer_debug_report_destroy_device(device);
-    get_dispatch_table(unique_objects_device_table_map, device)->DestroyDevice(device, pAllocator);
-    layer_data_map.erase(key);
-}
-
-VkResult explicit_AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
-                                 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
-    const VkMemoryAllocateInfo *input_allocate_info = pAllocateInfo;
-    std::unique_ptr<safe_VkMemoryAllocateInfo> safe_allocate_info;
-    std::unique_ptr<safe_VkDedicatedAllocationMemoryAllocateInfoNV> safe_dedicated_allocate_info;
-    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-
-    if ((pAllocateInfo != nullptr) &&
-        ContainsExtStruct(pAllocateInfo, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV)) {
-        // Assuming there is only one extension struct of this type in the list for now
-        safe_dedicated_allocate_info =
-            std::unique_ptr<safe_VkDedicatedAllocationMemoryAllocateInfoNV>(new safe_VkDedicatedAllocationMemoryAllocateInfoNV);
-        safe_allocate_info = std::unique_ptr<safe_VkMemoryAllocateInfo>(new safe_VkMemoryAllocateInfo);
-
-        safe_allocate_info->initialize(pAllocateInfo);
-        input_allocate_info = reinterpret_cast<const VkMemoryAllocateInfo *>(safe_allocate_info.get());
-
-        const GenericHeader *orig_pnext = reinterpret_cast<const GenericHeader *>(pAllocateInfo->pNext);
-        GenericHeader *input_pnext = reinterpret_cast<GenericHeader *>(safe_allocate_info.get());
-        while (orig_pnext != nullptr) {
-            if (orig_pnext->sType == VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV) {
-                safe_dedicated_allocate_info->initialize(
-                    reinterpret_cast<const VkDedicatedAllocationMemoryAllocateInfoNV *>(orig_pnext));
-
-                std::unique_lock<std::mutex> lock(global_lock);
-
-                if (safe_dedicated_allocate_info->buffer != VK_NULL_HANDLE) {
-                    uint64_t local_buffer = reinterpret_cast<uint64_t &>(safe_dedicated_allocate_info->buffer);
-                    safe_dedicated_allocate_info->buffer =
-                        reinterpret_cast<VkBuffer &>(my_map_data->unique_id_mapping[local_buffer]);
-                }
-
-                if (safe_dedicated_allocate_info->image != VK_NULL_HANDLE) {
-                    uint64_t local_image = reinterpret_cast<uint64_t &>(safe_dedicated_allocate_info->image);
-                    safe_dedicated_allocate_info->image = reinterpret_cast<VkImage &>(my_map_data->unique_id_mapping[local_image]);
-                }
-
-                lock.unlock();
-
-                input_pnext->pNext = reinterpret_cast<GenericHeader *>(safe_dedicated_allocate_info.get());
-                input_pnext = reinterpret_cast<GenericHeader *>(input_pnext->pNext);
-            } else {
-                // TODO: generic handling of pNext copies
-            }
-
-            orig_pnext = reinterpret_cast<const GenericHeader *>(orig_pnext->pNext);
-        }
-    }
-
-    VkResult result = get_dispatch_table(unique_objects_device_table_map, device)
-                          ->AllocateMemory(device, input_allocate_info, pAllocator, pMemory);
-
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        uint64_t unique_id = global_unique_id++;
-        my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*pMemory);
-        *pMemory = reinterpret_cast<VkDeviceMemory &>(unique_id);
-    }
-
-    return result;
-}
-
-VkResult explicit_CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                         const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
-                                         VkPipeline *pPipelines) {
-    // STRUCT USES:{'pipelineCache': 'VkPipelineCache', 'pCreateInfos[createInfoCount]': {'stage': {'module': 'VkShaderModule'},
-    // 'layout': 'VkPipelineLayout', 'basePipelineHandle': 'VkPipeline'}}
-    // LOCAL DECLS:{'pCreateInfos': 'VkComputePipelineCreateInfo*'}
-    layer_data *my_device_data = get_my_data_ptr(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 =
-                    (VkPipeline)my_device_data
-                        ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)];
-            }
-            if (pCreateInfos[idx0].layout) {
-                local_pCreateInfos[idx0].layout =
-                    (VkPipelineLayout)
-                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].layout)];
-            }
-            if (pCreateInfos[idx0].stage.module) {
-                local_pCreateInfos[idx0].stage.module =
-                    (VkShaderModule)
-                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].stage.module)];
-            }
-        }
-    }
-    if (pipelineCache) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)];
-    }
-
-    VkResult result = get_dispatch_table(unique_objects_device_table_map, device)
-                          ->CreateComputePipelines(device, pipelineCache, createInfoCount,
-                                                   (const VkComputePipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines);
-    delete[] local_pCreateInfos;
-    if (VK_SUCCESS == result) {
-        uint64_t unique_id = 0;
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < createInfoCount; ++i) {
-            unique_id = global_unique_id++;
-            my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]);
-            pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id);
-        }
-    }
-    return result;
-}
-
-VkResult explicit_CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount,
-                                          const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
-                                          VkPipeline *pPipelines) {
-    // STRUCT USES:{'pipelineCache': 'VkPipelineCache', 'pCreateInfos[createInfoCount]': {'layout': 'VkPipelineLayout',
-    // 'pStages[stageCount]': {'module': 'VkShaderModule'}, 'renderPass': 'VkRenderPass', 'basePipelineHandle': 'VkPipeline'}}
-    // LOCAL DECLS:{'pCreateInfos': 'VkGraphicsPipelineCreateInfo*'}
-    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = NULL;
-    if (pCreateInfos) {
-        local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount];
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
-            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]);
-            if (pCreateInfos[idx0].basePipelineHandle) {
-                local_pCreateInfos[idx0].basePipelineHandle =
-                    (VkPipeline)my_device_data
-                        ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)];
-            }
-            if (pCreateInfos[idx0].layout) {
-                local_pCreateInfos[idx0].layout =
-                    (VkPipelineLayout)
-                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(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 =
-                            (VkShaderModule)my_device_data
-                                ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].pStages[idx1].module)];
-                    }
-                }
-            }
-            if (pCreateInfos[idx0].renderPass) {
-                local_pCreateInfos[idx0].renderPass =
-                    (VkRenderPass)
-                        my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].renderPass)];
-            }
-        }
-    }
-    if (pipelineCache) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)];
-    }
-
-    VkResult result =
-        get_dispatch_table(unique_objects_device_table_map, device)
-            ->CreateGraphicsPipelines(device, pipelineCache, createInfoCount,
-                                      (const VkGraphicsPipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines);
-    delete[] local_pCreateInfos;
-    if (VK_SUCCESS == result) {
-        uint64_t unique_id = 0;
-        std::lock_guard<std::mutex> lock(global_lock);
-        for (uint32_t i = 0; i < createInfoCount; ++i) {
-            unique_id = global_unique_id++;
-            my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]);
-            pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id);
-        }
-    }
-    return result;
-}
-
-VkResult explicit_CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
-                                     const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
-    layer_data *my_map_data = get_my_data_ptr(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 =
-            (VkSwapchainKHR)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->oldSwapchain)];
-        // Need to pull surface mapping from the instance-level map
-        layer_data *instance_data = get_my_data_ptr(get_dispatch_key(my_map_data->gpu), layer_data_map);
-        local_pCreateInfo->surface =
-            (VkSurfaceKHR)instance_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->surface)];
-    }
-
-    VkResult result = get_dispatch_table(unique_objects_device_table_map, device)
-                          ->CreateSwapchainKHR(device, (const VkSwapchainCreateInfoKHR *)local_pCreateInfo, pAllocator, pSwapchain);
-    if (local_pCreateInfo)
-        delete local_pCreateInfo;
-    if (VK_SUCCESS == result) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        uint64_t unique_id =global_unique_id++;
-        my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*pSwapchain);
-        *pSwapchain = reinterpret_cast<VkSwapchainKHR &>(unique_id);
-    }
-    return result;
-}
-
-VkResult explicit_GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
-                                        VkImage *pSwapchainImages) {
-    // UNWRAP USES:
-    //  0 : swapchain,VkSwapchainKHR, pSwapchainImages,VkImage
-    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    if (VK_NULL_HANDLE != swapchain) {
-        std::lock_guard<std::mutex> lock(global_lock);
-        swapchain = (VkSwapchainKHR)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(swapchain)];
-    }
-    VkResult result = get_dispatch_table(unique_objects_device_table_map, device)
-                          ->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
-    // TODO : Need to add corresponding code to delete these images
-    if (VK_SUCCESS == result) {
-        if ((*pSwapchainImageCount > 0) && pSwapchainImages) {
-            uint64_t unique_id = 0;
-            std::lock_guard<std::mutex> lock(global_lock);
-            for (uint32_t i = 0; i < *pSwapchainImageCount; ++i) {
-                unique_id = global_unique_id++;
-                my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pSwapchainImages[i]);
-                pSwapchainImages[i] = reinterpret_cast<VkImage &>(unique_id);
-            }
-        }
-    }
-    return result;
-}
-
- #ifndef __ANDROID__
-VkResult explicit_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties)
-{
-    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
-    safe_VkDisplayPropertiesKHR* local_pProperties = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        if (pProperties) {
-            local_pProperties = new safe_VkDisplayPropertiesKHR[*pPropertyCount];
-            for (uint32_t idx0=0; idx0<*pPropertyCount; ++idx0) {
-                local_pProperties[idx0].initialize(&pProperties[idx0]);
-                if (pProperties[idx0].display) {
-                    local_pProperties[idx0].display = (VkDisplayKHR)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pProperties[idx0].display)];
-                }
-            }
-        }
-    }
-
-    VkResult result = get_dispatch_table(unique_objects_instance_table_map, physicalDevice)->GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, ( VkDisplayPropertiesKHR*)local_pProperties);
-    if (result == VK_SUCCESS && pProperties)
-    {
-        for (uint32_t idx0=0; idx0<*pPropertyCount; ++idx0) {
-            std::lock_guard<std::mutex> lock(global_lock);
-
-            uint64_t unique_id = global_unique_id++;
-            my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(local_pProperties[idx0].display);
-            pProperties[idx0].display = reinterpret_cast<VkDisplayKHR&>(unique_id);
-            pProperties[idx0].displayName = local_pProperties[idx0].displayName;
-            pProperties[idx0].physicalDimensions = local_pProperties[idx0].physicalDimensions;
-            pProperties[idx0].physicalResolution = local_pProperties[idx0].physicalResolution;
-            pProperties[idx0].supportedTransforms = local_pProperties[idx0].supportedTransforms;
-            pProperties[idx0].planeReorderPossible = local_pProperties[idx0].planeReorderPossible;
-            pProperties[idx0].persistentContent = local_pProperties[idx0].persistentContent;
-        }
-    }
-    if (local_pProperties)
-        delete[] local_pProperties;
-    return result;
-}
-
-VkResult explicit_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays)
-{
-    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
-    VkResult result = get_dispatch_table(unique_objects_instance_table_map, physicalDevice)->GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
-    if (VK_SUCCESS == result) {
-        if ((*pDisplayCount > 0) && pDisplays) {
-            std::lock_guard<std::mutex> lock(global_lock);
-            for (uint32_t i = 0; i < *pDisplayCount; i++) {
-                   auto it = my_map_data->unique_id_mapping.find(reinterpret_cast<const uint64_t &> (pDisplays[i]));
-                assert (it !=  my_map_data->unique_id_mapping.end());
-                pDisplays[i] = reinterpret_cast<VkDisplayKHR&> (it->second);
-            }
-        }
-    }
-    return result;
-}
-
-
-VkResult explicit_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties)
-{
-    layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
-    safe_VkDisplayModePropertiesKHR* local_pProperties = NULL;
-    {
-        std::lock_guard<std::mutex> lock(global_lock);
-        display = (VkDisplayKHR)my_map_data->unique_id_mapping[reinterpret_cast<uint64_t &>(display)];
-        if (pProperties) {
-            local_pProperties = new safe_VkDisplayModePropertiesKHR[*pPropertyCount];
-            for (uint32_t idx0=0; idx0<*pPropertyCount; ++idx0) {
-                local_pProperties[idx0].initialize(&pProperties[idx0]);
-            }
-        }
-    }
-
-    VkResult result = get_dispatch_table(unique_objects_instance_table_map, physicalDevice)->GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, ( VkDisplayModePropertiesKHR*)local_pProperties);
-    if (result == VK_SUCCESS && pProperties)
-    {
-        for (uint32_t idx0=0; idx0<*pPropertyCount; ++idx0) {
-            std::lock_guard<std::mutex> lock(global_lock);
-
-            uint64_t unique_id = global_unique_id++;
-            my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(local_pProperties[idx0].displayMode);
-            pProperties[idx0].displayMode = reinterpret_cast<VkDisplayModeKHR&>(unique_id);
-            pProperties[idx0].parameters.visibleRegion.width = local_pProperties[idx0].parameters.visibleRegion.width;
-            pProperties[idx0].parameters.visibleRegion.height = local_pProperties[idx0].parameters.visibleRegion.height;
-            pProperties[idx0].parameters.refreshRate = local_pProperties[idx0].parameters.refreshRate;
-        }
-    }
-    if (local_pProperties)
-        delete[] local_pProperties;
-    return result;
-}
-#endif
 } // namespace unique_objects
index 11405e3..3dae24c 100644 (file)
@@ -209,11 +209,9 @@ static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(debug_repor
     if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) {
         return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
     }
-
     if (!strcmp(funcName, "vkDebugReportMessageEXT")) {
         return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
     }
-
     return NULL;
 }
 
diff --git a/vk-layer-generate.py b/vk-layer-generate.py
deleted file mode 100755 (executable)
index 015826f..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-#!/usr/bin/env python3
-#
-# VK
-#
-# 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: Courtney Goeltzenleuchter <courtneygo@google.com>
-# Author: Jon Ashburn <jon@lunarg.com>
-# Author: Mark Lobodzinski <mark@lunarg.com>
-# Author: Mike Stroyan <stroyan@google.com>
-# Author: Tony Barbour <tony@LunarG.com>
-# Author: Chia-I Wu <olv@google.com>
-# Author: Gwan-gyeong Mun <kk.moon@samsung.com>
-
-import sys
-import os
-import re
-
-import vulkan
-import vk_helper
-from source_line_info import sourcelineinfo
-from collections import defaultdict
-
-def proto_is_global(proto):
-    global_function_names = [
-        "CreateInstance",
-        "EnumerateInstanceLayerProperties",
-        "EnumerateInstanceExtensionProperties",
-        "EnumerateDeviceLayerProperties",
-        "EnumerateDeviceExtensionProperties",
-        "CreateXcbSurfaceKHR",
-        "GetPhysicalDeviceXcbPresentationSupportKHR",
-        "CreateXlibSurfaceKHR",
-        "GetPhysicalDeviceXlibPresentationSupportKHR",
-        "CreateWaylandSurfaceKHR",
-        "GetPhysicalDeviceWaylandPresentationSupportKHR",
-        "CreateMirSurfaceKHR",
-        "GetPhysicalDeviceMirPresentationSupportKHR",
-        "CreateAndroidSurfaceKHR",
-        "CreateWin32SurfaceKHR",
-        "GetPhysicalDeviceWin32PresentationSupportKHR",
-        "GetPhysicalDeviceDisplayPropertiesKHR",
-        "GetPhysicalDeviceDisplayPlanePropertiesKHR",
-        "GetDisplayPlaneSupportedDisplaysKHR",
-        "GetDisplayModePropertiesKHR",
-        "CreateDisplayModeKHR",
-        "GetDisplayPlaneCapabilitiesKHR",
-        "CreateDisplayPlaneSurfaceKHR"
-    ]
-    if proto.params[0].ty == "VkInstance" or proto.params[0].ty == "VkPhysicalDevice" or proto.name in global_function_names:
-       return True
-    else:
-       return False
-
-def wsi_name(ext_name):
-    wsi_prefix = ""
-    if 'Xcb' in ext_name:
-        wsi_prefix = 'XCB'
-    elif 'Xlib' in ext_name:
-        wsi_prefix = 'XLIB'
-    elif 'Win32' in ext_name:
-        wsi_prefix = 'WIN32'
-    elif 'Mir' in ext_name:
-        wsi_prefix = 'MIR'
-    elif 'Wayland' in ext_name:
-        wsi_prefix = 'WAYLAND'
-    elif 'Android' in ext_name:
-        wsi_prefix = 'ANDROID'
-    else:
-        wsi_prefix = ''
-    return wsi_prefix
-
-def wsi_ifdef(ext_name):
-    wsi_prefix = wsi_name(ext_name)
-    if not wsi_prefix:
-        return ''
-    else:
-        return "#ifdef VK_USE_PLATFORM_%s_KHR" % wsi_prefix
-
-def wsi_endif(ext_name):
-    wsi_prefix = wsi_name(ext_name)
-    if not wsi_prefix:
-        return ''
-    else:
-        return "#endif  // VK_USE_PLATFORM_%s_KHR" % wsi_prefix
-
-def generate_get_proc_addr_check(name):
-    return "    if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
-           "        return NULL;" % ((name,) * 3)
-
-def ucc_to_U_C_C(CamelCase):
-    temp = re.sub('(.)([A-Z][a-z]+)',  r'\1_\2', CamelCase)
-    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', temp).upper()
-
-# Parse complete struct chain and add any new ndo_uses to the dict
-def gather_object_uses_in_struct(obj_list, struct_type):
-    struct_uses = {}
-    if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict:
-        struct_type = vk_helper.typedef_rev_dict[struct_type]
-        # Parse elements of this struct param to identify objects and/or arrays of objects
-        for m in sorted(vk_helper.struct_dict[struct_type]):
-            array_len = "%s" % (str(vk_helper.struct_dict[struct_type][m]['array_size']))
-            base_type = vk_helper.struct_dict[struct_type][m]['type']
-            mem_name = vk_helper.struct_dict[struct_type][m]['name']
-            if array_len != '0':
-                mem_name = "%s[%s]" % (mem_name, array_len)
-            if base_type in obj_list:
-                #if array_len not in ndo_uses:
-                #    struct_uses[array_len] = []
-                #struct_uses[array_len].append("%s%s,%s" % (name_prefix, struct_name, base_type))
-                struct_uses[mem_name] = base_type
-            elif vk_helper.is_type(base_type, 'struct'):
-                sub_uses = gather_object_uses_in_struct(obj_list, base_type)
-                if len(sub_uses) > 0:
-                    struct_uses[mem_name] = sub_uses
-    return struct_uses
-
-# For the given list of object types, Parse the given list of params
-#  and return dict of params that use one of the obj_list types
-# Format of the dict is that terminal elements have <name>,<type>
-#  non-terminal elements will have <name>[<array_size>]
-# TODO : This analysis could be done up-front at vk_helper time
-def get_object_uses(obj_list, params):
-    obj_uses = {}
-    local_decls = {}
-    param_count = 'NONE' # track params that give array sizes
-    for p in params:
-        base_type = p.ty.replace('const ', '').strip('*')
-        array_len = ''
-        is_ptr = False
-        if 'count' in p.name.lower():
-            param_count = p.name
-        ptr_txt = ''
-        if '*' in p.ty:
-            is_ptr = True
-            ptr_txt = '*'
-        if base_type in obj_list:
-            if is_ptr and 'const' in p.ty and param_count != 'NONE':
-                array_len = "[%s]" % param_count
-                # Non-arrays we can overwrite in place, but need local decl for arrays
-                local_decls[p.name] = '%s%s' % (base_type, ptr_txt)
-            #if array_len not in obj_uses:
-            #    obj_uses[array_len] = {}
-            # obj_uses[array_len][p.name] = base_type
-            obj_uses["%s%s" % (p.name, array_len)] = base_type
-        elif vk_helper.is_type(base_type, 'struct'):
-            struct_name = p.name
-            if 'NONE' != param_count:
-                struct_name = "%s[%s]" % (struct_name, param_count)
-            struct_uses = gather_object_uses_in_struct(obj_list, base_type)
-            if len(struct_uses) > 0:
-                obj_uses[struct_name] = struct_uses
-                # This is a top-level struct w/ uses below it, so need local decl
-                local_decls['%s' % (p.name)] = '%s%s' % (base_type, ptr_txt)
-    return (obj_uses, local_decls)
-
-class Subcommand(object):
-    def __init__(self, outfile):
-        self.outfile = outfile
-        self.headers = vulkan.headers
-        self.protos = vulkan.protos
-        self.no_addr = False
-        self.layer_name = ""
-        self.lineinfo = sourcelineinfo()
-        self.wsi = sys.argv[1]
-
-    def run(self):
-        if self.outfile:
-            with open(self.outfile, "w") as outfile:
-                outfile.write(self.generate())
-        else:
-            print(self.generate())
-
-    def generate(self):
-        copyright = self.generate_copyright()
-        header = self.generate_header()
-        body = self.generate_body()
-        footer = self.generate_footer()
-
-        contents = []
-        if copyright:
-            contents.append(copyright)
-        if header:
-            contents.append(header)
-        if body:
-            contents.append(body)
-        if footer:
-            contents.append(footer)
-
-        return "\n\n".join(contents)
-
-    def generate_copyright(self):
-        return """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
-
-/*
- * 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: Courtney Goeltzenleuchter <courtneygo@google.com>
- * Author: Jon Ashburn <jon@lunarg.com>
- * Author: Mark Lobodzinski <mark@lunarg.com>
- * Author: Mike Stroyan <stroyan@google.com>
- * Author: Tony Barbour <tony@LunarG.com>
- */"""
-
-    def generate_header(self):
-        return "\n".join(["#include <" + h + ">" for h in self.headers])
-
-    def generate_body(self):
-        pass
-
-    def generate_footer(self):
-        pass
-
-    # Return set of printf '%' qualifier and input to that qualifier
-    def _get_printf_params(self, vk_type, name, output_param, cpp=False):
-        # TODO : Need ENUM and STRUCT checks here
-        if vk_helper.is_type(vk_type, 'enum'):#"_TYPE" in vk_type: # TODO : This should be generic ENUM check
-            return ("%s", "string_%s(%s)" % (vk_type.replace('const ', '').strip('*'), name))
-        if "char*" == vk_type:
-            return ("%s", name)
-        if "uint64" in vk_type:
-            if '*' in vk_type:
-                return ("%lu", "*%s" % name)
-            return ("%lu", name)
-        if vk_type.strip('*') in vulkan.object_non_dispatch_list:
-            if '*' in vk_type:
-                return ("%lu", "%s" % name)
-            return ("%lu", "%s" % name)
-        if "size" in vk_type:
-            if '*' in vk_type:
-                return ("%lu", "(unsigned long)*%s" % name)
-            return ("%lu", "(unsigned long)%s" % name)
-        if "float" in vk_type:
-            if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
-                if cpp:
-                    return ("[%i, %i, %i, %i]", '"[" << %s[0] << "," << %s[1] << "," << %s[2] << "," << %s[3] << "]"' % (name, name, name, name))
-                return ("[%f, %f, %f, %f]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
-            return ("%f", name)
-        if "bool" in vk_type.lower() or 'xcb_randr_crtc_t' in vk_type:
-            return ("%u", name)
-        if True in [t in vk_type.lower() for t in ["int", "flags", "mask", "xcb_window_t"]]:
-            if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
-                if cpp:
-                    return ("[%i, %i, %i, %i]", "%s[0] << %s[1] << %s[2] << %s[3]" % (name, name, name, name))
-                return ("[%i, %i, %i, %i]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
-            if '*' in vk_type:
-                if 'pUserData' == name:
-                    return ("%i", "((pUserData == 0) ? 0 : *(pUserData))")
-                if 'const' in vk_type.lower():
-                    return ("0x%p", "(void*)(%s)" % name)
-                return ("%i", "*(%s)" % name)
-            return ("%i", name)
-        # TODO : This is special-cased as there's only one "format" param currently and it's nice to expand it
-        if "VkFormat" == vk_type:
-            if cpp:
-                return ("0x%p", "&%s" % name)
-            return ("{%s.channelFormat = %%s, %s.numericFormat = %%s}" % (name, name), "string_VK_COLOR_COMPONENT_FORMAT(%s.channelFormat), string_VK_FORMAT_RANGE_SIZE(%s.numericFormat)" % (name, name))
-        if output_param:
-            return ("0x%p", "(void*)*%s" % name)
-        if vk_helper.is_type(vk_type, 'struct') and '*' not in vk_type:
-            return ("0x%p", "(void*)(&%s)" % name)
-        return ("0x%p", "(void*)(%s)" % name)
-
-    def _gen_create_msg_callback(self):
-        r_body = []
-        r_body.append('%s' % self.lineinfo.get())
-        r_body.append('VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(')
-        r_body.append('        VkInstance                                   instance,')
-        r_body.append('        const VkDebugReportCallbackCreateInfoEXT*    pCreateInfo,')
-        r_body.append('        const VkAllocationCallbacks*                 pAllocator,')
-        r_body.append('        VkDebugReportCallbackEXT*                    pCallback)')
-        r_body.append('{')
-        # Switch to this code section for the new per-instance storage and debug callbacks
-        if self.layer_name in ['unique_objects']:
-            r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name )
-            r_body.append('    VkResult result = pInstanceTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);')
-            r_body.append('    if (VK_SUCCESS == result) {')
-            r_body.append('        layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
-            r_body.append('        result = layer_create_msg_callback(my_data->report_data,')
-            r_body.append('                                           false,')
-            r_body.append('                                           pCreateInfo,')
-            r_body.append('                                           pAllocator,')
-            r_body.append('                                           pCallback);')
-            r_body.append('    }')
-            r_body.append('    return result;')
-        else:
-            r_body.append('    VkResult result = instance_dispatch_table(instance)->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);')
-            r_body.append('    if (VK_SUCCESS == result) {')
-            r_body.append('        layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
-            r_body.append('        result = layer_create_msg_callback(my_data->report_data, false, pCreateInfo, pAllocator, pCallback);')
-            r_body.append('    }')
-            r_body.append('    return result;')
-        r_body.append('}')
-        return "\n".join(r_body)
-
-    def _gen_destroy_msg_callback(self):
-        r_body = []
-        r_body.append('%s' % self.lineinfo.get())
-        r_body.append('VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, const VkAllocationCallbacks *pAllocator)')
-        r_body.append('{')
-        # Switch to this code section for the new per-instance storage and debug callbacks
-        if self.layer_name in ['unique_objects']:
-            r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name )
-        else:
-            r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);')
-        r_body.append('    pInstanceTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);')
-        r_body.append('    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
-        r_body.append('    layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);')
-        r_body.append('}')
-        return "\n".join(r_body)
-
-    def _gen_debug_report_msg(self):
-        r_body = []
-        r_body.append('%s' % self.lineinfo.get())
-        r_body.append('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)')
-        r_body.append('{')
-        # Switch to this code section for the new per-instance storage and debug callbacks
-        r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);')
-        r_body.append('    pInstanceTable->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);')
-        r_body.append('}')
-        return "\n".join(r_body)
-
-    def _gen_layer_logging_workaround(self):
-        body = []
-        body.append('%s' % self.lineinfo.get())
-        body.append('// vk_layer_logging.h expects these to be defined')
-        body.append('')
-        body.append('VKAPI_ATTR VkResult VKAPI_CALL')
-        body.append('vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,')
-        body.append('                               const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {')
-        body.append('    return %s::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance,')
-        body.append('                                                                           VkDebugReportCallbackEXT msgCallback,')
-        body.append('                                                                           const VkAllocationCallbacks *pAllocator) {')
-        body.append('    %s::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VKAPI_ATTR void VKAPI_CALL')
-        body.append('vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,')
-        body.append('                        size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {')
-        body.append('    %s::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);' % self.layer_name)
-        body.append('}')
-
-        return "\n".join(body)
-
-    def _gen_layer_interface_v0_functions(self):
-        body = []
-        body.append('%s' % self.lineinfo.get())
-        body.append('// loader-layer interface v0, just wrappers since there is only a layer')
-        body.append('')
-
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,  VkExtensionProperties* pProperties)')
-        body.append('{')
-        body.append('    return %s::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,  VkLayerProperties* pProperties)')
-        body.append('{')
-        body.append('    return %s::EnumerateInstanceLayerProperties(pCount, pProperties);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties* pProperties)')
-        body.append('{')
-        body.append('    // the layer command handles VK_NULL_HANDLE just fine internally')
-        body.append('    assert(physicalDevice == VK_NULL_HANDLE);')
-        body.append('    return %s::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName)')
-        body.append('{')
-        body.append('    return %s::GetDeviceProcAddr(dev, funcName);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName)')
-        body.append('{')
-        body.append('    return %s::GetInstanceProcAddr(instance, funcName);' % self.layer_name)
-        body.append('}')
-        body.append('')
-        body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,')
-        body.append('                                                                                    const char *pLayerName, uint32_t *pCount,')
-        body.append('                                                                                    VkExtensionProperties *pProperties)')
-        body.append('{')
-        body.append('    // the layer command handles VK_NULL_HANDLE just fine internally')
-        body.append('    assert(physicalDevice == VK_NULL_HANDLE);')
-        body.append('    return %s::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);' % self.layer_name)
-        body.append('}')
-
-        return "\n".join(body)
-
-    def _generate_dispatch_entrypoints(self, qual=""):
-        if qual:
-            qual += " "
-
-        funcs = []
-        intercepted = []
-        for proto in self.protos:
-            if proto.name in ["EnumerateInstanceExtensionProperties",
-                              "EnumerateInstanceLayerProperties",
-                              "EnumerateDeviceLayerProperties",
-                              "GetDeviceProcAddr",
-                              "GetInstanceProcAddr"]:
-                funcs.append(proto.c_func(attr="VKAPI") + ';')
-                intercepted.append(proto)
-            else:
-                intercept = self.generate_intercept(proto, qual)
-                if intercept is None:
-                    # fill in default intercept for certain entrypoints
-                    if 'CreateDebugReportCallbackEXT' == proto.name:
-                        intercept = self._gen_layer_dbg_create_msg_callback()
-                    elif 'DestroyDebugReportCallbackEXT' == proto.name:
-                        intercept = self._gen_layer_dbg_destroy_msg_callback()
-                    elif 'DebugReportMessageEXT' == proto.name:
-                        intercept = self._gen_debug_report_msg()
-                    elif 'CreateDevice' == proto.name:
-                        funcs.append('/* CreateDevice HERE */')
-
-                if intercept is not None:
-                    funcs.append(intercept)
-                    if not "KHR" in proto.name:
-                        intercepted.append(proto)
-
-        instance_lookups = []
-        device_lookups = []
-        for proto in intercepted:
-            if proto_is_global(proto):
-                instance_lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
-                instance_lookups.append("    return (PFN_vkVoidFunction) %s;" % (proto.name))
-            else:
-                device_lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
-                device_lookups.append("    return (PFN_vkVoidFunction) %s;" % (proto.name))
-
-        # add customized intercept_core_device_command
-        body = []
-        body.append('%s' % self.lineinfo.get())
-        body.append("static inline PFN_vkVoidFunction intercept_core_device_command(const char *name)")
-        body.append("{")
-        body.append(generate_get_proc_addr_check("name"))
-        body.append("")
-        body.append("    name += 2;")
-        body.append("    %s" % "\n    ".join(device_lookups))
-        body.append("")
-        body.append("    return NULL;")
-        body.append("}")
-        # add intercept_core_instance_command
-        body.append("static inline PFN_vkVoidFunction intercept_core_instance_command(const char *name)")
-        body.append("{")
-        body.append(generate_get_proc_addr_check("name"))
-        body.append("")
-        body.append("    name += 2;")
-        body.append("    %s" % "\n    ".join(instance_lookups))
-        body.append("")
-        body.append("    return NULL;")
-        body.append("}")
-
-        funcs.append("\n".join(body))
-        return "\n\n".join(funcs)
-
-    def _generate_extensions(self):
-        exts = []
-        exts.append('%s' % self.lineinfo.get())
-        exts.append(self._gen_create_msg_callback())
-        exts.append(self._gen_destroy_msg_callback())
-        exts.append(self._gen_debug_report_msg())
-        return "\n".join(exts)
-
-    def _generate_layer_introspection_function(self):
-        body = []
-        body.append('%s' % self.lineinfo.get())
-        body.append('static const VkLayerProperties globalLayerProps = {')
-        body.append('    "VK_LAYER_GOOGLE_%s",' % self.layer_name)
-        body.append('    VK_LAYER_API_VERSION, // specVersion')
-        body.append('    1, // implementationVersion')
-        body.append('    "Google Validation Layer"')
-        body.append('};')
-        body.append('')
-
-        body.append('VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount,  VkLayerProperties* pProperties)')
-        body.append('{')
-        body.append('    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);')
-        body.append('}')
-        body.append('')
-        body.append('VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties* pProperties)')
-        body.append('{')
-        body.append('    return util_GetLayerProperties(1, &globalLayerProps, pCount, pProperties);')
-        body.append('}')
-        body.append('')
-        body.append('VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,  VkExtensionProperties* pProperties)')
-        body.append('{')
-        body.append('    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))')
-        body.append('        return util_GetExtensionProperties(0, NULL, pCount, pProperties);')
-        body.append('')
-        body.append('    return VK_ERROR_LAYER_NOT_PRESENT;')
-        body.append('}')
-        body.append('')
-        body.append('VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,')
-        body.append('                                                                  const char *pLayerName, uint32_t *pCount,')
-        body.append('                                                                  VkExtensionProperties *pProperties)')
-        body.append('{')
-        body.append('    if (pLayerName && !strcmp(pLayerName, globalLayerProps.layerName))')
-        body.append('        return util_GetExtensionProperties(0, nullptr, pCount, pProperties);')
-        body.append('')
-        body.append('    assert(physicalDevice);')
-        body.append('    VkLayerInstanceDispatchTable* pTable = get_dispatch_table(%s_instance_table_map, physicalDevice);' % self.layer_name)
-        body.append('    return pTable->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);')
-        body.append('}')
-
-        return "\n".join(body)
-
-    def _generate_layer_gpa_function(self, extensions=[], instance_extensions=[]):
-        func_body = []
-#
-# New style of GPA Functions for the new layer_data/layer_logging changes
-#
-        if self.layer_name in ['unique_objects']:
-            for ext_enable, ext_list in extensions:
-                func_body.append('%s' % self.lineinfo.get())
-                func_body.append('static inline PFN_vkVoidFunction intercept_%s_command(const char *name, VkDevice dev)' % ext_enable)
-                func_body.append('{')
-                func_body.append('    if (dev) {')
-                func_body.append('        layer_data *my_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);')
-                func_body.append('        if (!my_data->%s)' % ext_enable)
-                func_body.append('            return nullptr;')
-                func_body.append('    }\n')
-
-                for ext_name in ext_list:
-                    func_body.append('    if (!strcmp("%s", name))\n'
-                                     '        return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (ext_name, ext_name[2:]))
-                func_body.append('\n    return nullptr;')
-                func_body.append('}\n')
-
-            func_body.append("VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char* funcName)\n"
-                             "{\n"
-                             "    PFN_vkVoidFunction addr;\n"
-                             "    addr = intercept_core_device_command(funcName);\n"
-                             "    if (addr)\n"
-                             "        return addr;\n"
-                             "    assert(device);\n")
-            for ext_enable, _ in extensions:
-                func_body.append('    addr = intercept_%s_command(funcName, device);' % ext_enable)
-                func_body.append('    if (addr)\n'
-                                 '        return addr;')
-            func_body.append("\n    if (get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr == NULL)\n"
-                             "        return NULL;\n"
-                             "    return get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr(device, funcName);\n"
-                             "}\n" % (self.layer_name, self.layer_name))
-
-            # The WSI-related extensions have independent extension enables
-            wsi_sub_enables = {'WIN32': 'win32_enabled',
-                               'XLIB': 'xlib_enabled',
-                               'XCB': 'xcb_enabled',
-                               'MIR': 'mir_enabled',
-                               'WAYLAND': 'wayland_enabled',
-                               'ANDROID': 'android_enabled'}
-
-            for ext_enable, ext_list in instance_extensions:
-                func_body.append('%s' % self.lineinfo.get())
-                func_body.append('static inline PFN_vkVoidFunction intercept_%s_command(const char *name, VkInstance instance)' % ext_enable)
-                func_body.append('{')
-                if ext_enable == 'msg_callback_get_proc_addr':
-                    func_body.append("    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n"
-                                     "    return debug_report_get_instance_proc_addr(my_data->report_data, name);")
-                else:
-                    func_body.append("    VkLayerInstanceDispatchTable* pTable = get_dispatch_table(%s_instance_table_map, instance);" % self.layer_name)
-                    func_body.append('    if (instanceExtMap.size() == 0 || !instanceExtMap[pTable].%s)' % ext_enable)
-                    func_body.append('        return nullptr;\n')
-
-                    for ext_name in ext_list:
-                        if wsi_name(ext_name):
-                            func_body.append('%s' % wsi_ifdef(ext_name))
-                            if wsi_sub_enables[wsi_name(ext_name)]:
-                                func_body.append('    if ((instanceExtMap[pTable].%s == true) && !strcmp("%s", name))\n'
-                                                 '        return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (wsi_sub_enables[wsi_name(ext_name)], ext_name, ext_name[2:]))
-                        else:
-                            func_body.append('    if (!strcmp("%s", name))\n'
-                                             '        return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (ext_name, ext_name[2:]))
-                        if wsi_name(ext_name):
-                            func_body.append('%s' % wsi_endif(ext_name))
-
-                    func_body.append('\n    return nullptr;')
-                func_body.append('}\n')
-
-            func_body.append("VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char* funcName)\n"
-                             "{\n"
-                             "    PFN_vkVoidFunction addr;\n"
-                             "    addr = intercept_core_instance_command(funcName);\n"
-                             "    if (!addr) {\n"
-                             "        addr = intercept_core_device_command(funcName);\n"
-                             "    }")
-
-            for ext_enable, _ in extensions:
-                func_body.append("    if (!addr) {\n"
-                                 "        addr = intercept_%s_command(funcName, VkDevice(VK_NULL_HANDLE));\n"
-                                 "    }" % ext_enable)
-
-            func_body.append("    if (addr) {\n"
-                             "        return addr;\n"
-                             "    }\n"
-                             "    assert(instance);\n"
-                             )
-
-            for ext_enable, _ in instance_extensions:
-                func_body.append('    addr = intercept_%s_command(funcName, instance);' % ext_enable)
-                func_body.append('    if (addr)\n'
-                                 '        return addr;\n')
-
-            func_body.append("    if (get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr == NULL) {\n"
-                             "        return NULL;\n"
-                             "    }\n"
-                             "    return get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);\n"
-                             "}\n" % (self.layer_name, self.layer_name))
-            return "\n".join(func_body)
-        else:
-            func_body.append('%s' % self.lineinfo.get())
-            func_body.append("VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char* funcName)\n"
-                             "{\n"
-                             "    PFN_vkVoidFunction addr;\n")
-            func_body.append("\n"
-                             "    loader_platform_thread_once(&initOnce, init%s);\n\n"
-                             "    addr = intercept_core_device_command(funcName);\n"
-                             "    if (addr)\n"
-                             "        return addr;" % self.layer_name)
-            func_body.append("    assert(device);\n")
-            func_body.append('')
-            func_body.append('    VkLayerDispatchTable *pDisp =  device_dispatch_table(device);')
-            if 0 != len(extensions):
-                extra_space = ""
-                for (ext_enable, ext_list) in extensions:
-                    if 0 != len(ext_enable):
-                        func_body.append('    if (deviceExtMap.size() != 0 && deviceExtMap[pDisp].%s)' % ext_enable)
-                        func_body.append('    {')
-                        extra_space = "    "
-                    for ext_name in ext_list:
-                        func_body.append('    %sif (!strcmp("%s", funcName))\n'
-                                         '            return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name))
-                    if 0 != len(ext_enable):
-                        func_body.append('    }')
-            func_body.append('%s' % self.lineinfo.get())
-            func_body.append("    {\n"
-                             "        if (pDisp->GetDeviceProcAddr == NULL)\n"
-                             "            return NULL;\n"
-                             "        return pDisp->GetDeviceProcAddr(device, funcName);\n"
-                             "    }\n"
-                             "}\n")
-            func_body.append('%s' % self.lineinfo.get())
-            func_body.append("VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char* funcName)\n"
-                             "{\n"
-                             "    PFN_vkVoidFunction addr;\n"
-                             )
-            func_body.append(
-                             "    loader_platform_thread_once(&initOnce, init%s);\n\n"
-                             "    addr = intercept_core_instance_command(funcName);\n"
-                             "    if (addr)\n"
-                             "        return addr;" % self.layer_name)
-            func_body.append("    assert(instance);\n")
-            func_body.append("")
-            func_body.append("    VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);\n")
-            if 0 != len(instance_extensions):
-                extra_space = ""
-                for (ext_enable, ext_list) in instance_extensions:
-                    if 0 != len(ext_enable):
-                        if ext_enable == 'msg_callback_get_proc_addr':
-                            func_body.append("    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n"
-                                     "    addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);\n"
-                                     "    if (addr) {\n"
-                                     "        return addr;\n"
-                                     "    }\n")
-                        else:
-                            func_body.append('    if (instanceExtMap.size() != 0 && instanceExtMap[pTable].%s)' % ext_enable)
-                            func_body.append('    {')
-                            extra_space = "    "
-                            for ext_name in ext_list:
-                                if wsi_name(ext_name):
-                                    func_body.append('%s' % wsi_ifdef(ext_name))
-                                func_body.append('    %sif (!strcmp("%s", funcName))\n'
-                                         '            return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name))
-                                if wsi_name(ext_name):
-                                    func_body.append('%s' % wsi_endif(ext_name))
-                            if 0 != len(ext_enable):
-                                func_body.append('    }\n')
-
-            func_body.append("    if (pTable->GetInstanceProcAddr == NULL)\n"
-                             "        return NULL;\n"
-                             "    return pTable->GetInstanceProcAddr(instance, funcName);\n"
-                             "}\n")
-            return "\n".join(func_body)
-
-
-    def _generate_layer_initialization(self, init_opts=False, prefix='vk', lockname=None, condname=None):
-        func_body = ["#include \"vk_dispatch_table_helper.h\""]
-        func_body.append('%s' % self.lineinfo.get())
-        func_body.append('static void init_%s(layer_data *my_data, const VkAllocationCallbacks *pAllocator)\n'
-                         '{\n' % self.layer_name)
-        if init_opts:
-            func_body.append('%s' % self.lineinfo.get())
-            func_body.append('')
-            func_body.append('    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_%s");' % self.layer_name)
-            func_body.append('')
-        if lockname is not None:
-            func_body.append('%s' % self.lineinfo.get())
-            func_body.append("    if (!%sLockInitialized)" % lockname)
-            func_body.append("    {")
-            func_body.append("        // TODO/TBD: Need to delete this mutex sometime.  How???")
-            func_body.append("        loader_platform_thread_create_mutex(&%sLock);" % lockname)
-            if condname is not None:
-                func_body.append("        loader_platform_thread_init_cond(&%sCond);" % condname)
-            func_body.append("        %sLockInitialized = 1;" % lockname)
-            func_body.append("    }")
-        func_body.append("}\n")
-        func_body.append('')
-        return "\n".join(func_body)
-
-class UniqueObjectsSubcommand(Subcommand):
-    def generate_header(self):
-        header_txt = []
-        header_txt.append('%s' % self.lineinfo.get())
-        header_txt.append('#include "unique_objects.h"')
-        return "\n".join(header_txt)
-
-    # Generate UniqueObjects code for given struct_uses dict of objects that need to be unwrapped
-    # vector_name_set is used to make sure we don't replicate vector names
-    # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
-    # TODO : Comment this code
-    def _gen_obj_code(self, struct_uses, param_type, indent, prefix, array_index, vector_name_set, first_level_param):
-        decls = ''
-        pre_code = ''
-        post_code = ''
-        for obj in sorted(struct_uses):
-            name = obj
-            array = ''
-            if '[' in obj:
-                (name, array) = obj.split('[')
-                array = array.strip(']')
-            ptr_type = False
-            if 'p' == obj[0] and obj[1] != obj[1].lower(): # TODO : Not ideal way to determine ptr
-                ptr_type = True
-            if isinstance(struct_uses[obj], dict):
-                local_prefix = ''
-                name = '%s%s' % (prefix, name)
-                if ptr_type:
-                    if first_level_param and name in param_type:
-                        pre_code += '%sif (%s) {\n' % (indent, name)
-                    else: # shadow ptr will have been initialized at this point so check it vs. source ptr
-                        pre_code += '%sif (local_%s) {\n' % (indent, name)
-                    indent += '    '
-                if array != '':
-                    if 'p' == array[0] and array[1] != array[1].lower(): # TODO : Not ideal way to determine ptr
-                        count_prefix = '*'
-                    else:
-                        count_prefix = ''
-                    idx = 'idx%s' % str(array_index)
-                    array_index += 1
-                    if first_level_param and name in param_type:
-                        pre_code += '%slocal_%s = new safe_%s[%s%s];\n' % (indent, name, param_type[name].strip('*'), count_prefix, array)
-                        post_code += '    if (local_%s)\n' % (name)
-                        post_code += '        delete[] local_%s;\n' % (name)
-                    pre_code += '%sfor (uint32_t %s=0; %s<%s%s%s; ++%s) {\n' % (indent, idx, idx, count_prefix, prefix, array, idx)
-                    indent += '    '
-                    if first_level_param:
-                        pre_code += '%slocal_%s[%s].initialize(&%s[%s]);\n' % (indent, name, idx, name, idx)
-                    local_prefix = '%s[%s].' % (name, idx)
-                elif ptr_type:
-                    if first_level_param and name in param_type:
-                        pre_code += '%slocal_%s = new safe_%s(%s);\n' % (indent, name, param_type[name].strip('*'), name)
-                        post_code += '    if (local_%s)\n' % (name)
-                        post_code += '        delete local_%s;\n' % (name)
-                    local_prefix = '%s->' % (name)
-                else:
-                    local_prefix = '%s.' % (name)
-                assert isinstance(decls, object)
-                (tmp_decl, tmp_pre, tmp_post) = self._gen_obj_code(struct_uses[obj], param_type, indent, local_prefix, array_index, vector_name_set, False)
-                decls += tmp_decl
-                pre_code += tmp_pre
-                post_code += tmp_post
-                if array != '':
-                    indent = indent[4:]
-                    pre_code += '%s}\n' % (indent)
-                if ptr_type:
-                    indent = indent[4:]
-                    pre_code += '%s}\n' % (indent)
-            else:
-                if (array_index > 0) or array != '': # TODO : This is not ideal, really want to know if we're anywhere under an array
-                    if first_level_param:
-                        decls += '%s%s* local_%s = NULL;\n' % (indent, struct_uses[obj], name)
-                    if array != '' and not first_level_param: # ptrs under structs will have been initialized so use local_*
-                        pre_code += '%sif (local_%s%s) {\n' %(indent, prefix, name)
-                    else:
-                        pre_code += '%sif (%s%s) {\n' %(indent, prefix, name)
-                    indent += '    '
-                    if array != '':
-                        idx = 'idx%s' % str(array_index)
-                        array_index += 1
-                        if first_level_param:
-                            pre_code += '%slocal_%s = new %s[%s];\n' % (indent, name, struct_uses[obj], array)
-                            post_code += '    if (local_%s)\n' % (name)
-                            post_code += '        delete[] local_%s;\n' % (name)
-                        pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx)
-                        indent += '    '
-                        name = '%s[%s]' % (name, idx)
-                    if name not in vector_name_set:
-                        vector_name_set.add(name)
-                    pre_code += '%slocal_%s%s = (%s)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(%s%s)];\n' % (indent, prefix, name, struct_uses[obj], prefix, name)
-                    if array != '':
-                        indent = indent[4:]
-                        pre_code += '%s}\n' % (indent)
-                    indent = indent[4:]
-                    pre_code += '%s}\n' % (indent)
-                else:
-                    pre_code += '%s\n' % (self.lineinfo.get())
-                    if '->' in prefix: # need to update local struct
-                        pre_code += '%slocal_%s%s = (%s)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(%s%s)];\n' % (indent, prefix, name, struct_uses[obj], prefix, name)
-                    else:
-                        pre_code += '%s%s = (%s)my_map_data->unique_id_mapping[reinterpret_cast<uint64_t &>(%s)];\n' % (indent, name, struct_uses[obj], name)
-        return decls, pre_code, post_code
-
-    def generate_intercept(self, proto, qual):
-        create_func = False
-        destroy_func = False
-        last_param_index = None #typcially we look at all params for ndos
-        pre_call_txt = '' # code prior to calling down chain such as unwrap uses of ndos
-        post_call_txt = '' # code following call down chain such to wrap newly created ndos, or destroy local wrap struct
-        funcs = []
-        indent = '    ' # indent level for generated code
-        decl = proto.c_func(attr="VKAPI")
-        # A few API cases that are manual code
-        # TODO : Special case Create*Pipelines funcs to handle creating multiple unique objects
-        explicit_unique_objects_functions = ['GetSwapchainImagesKHR',
-                                             'CreateSwapchainKHR',
-                                             'CreateInstance',
-                                             'DestroyInstance',
-                                             'CreateDevice',
-                                             'DestroyDevice',
-                                             'AllocateMemory',
-                                             'CreateComputePipelines',
-                                             'CreateGraphicsPipelines',
-                                             'GetPhysicalDeviceDisplayPropertiesKHR',
-                                             'GetDisplayPlaneSupportedDisplaysKHR',
-                                             'GetDisplayModePropertiesKHR'
-                                             ]
-        # TODO : This is hacky, need to make this a more general-purpose solution for all layers
-        ifdef_dict = {'CreateXcbSurfaceKHR': 'VK_USE_PLATFORM_XCB_KHR',
-                      'CreateAndroidSurfaceKHR': 'VK_USE_PLATFORM_ANDROID_KHR',
-                      'CreateWin32SurfaceKHR': 'VK_USE_PLATFORM_WIN32_KHR',
-                      'CreateXlibSurfaceKHR': 'VK_USE_PLATFORM_XLIB_KHR',
-                      'CreateWaylandSurfaceKHR': 'VK_USE_PLATFORM_WAYLAND_KHR',
-                      'CreateMirSurfaceKHR': 'VK_USE_PLATFORM_MIR_KHR'}
-        # Give special treatment to create functions that return multiple new objects
-        # This dict stores array name and size of array
-        custom_create_dict = {'pDescriptorSets' : 'pAllocateInfo->descriptorSetCount'}
-        pre_call_txt += '%s\n' % (self.lineinfo.get())
-        if proto.name in explicit_unique_objects_functions:
-            funcs.append('%s%s\n'
-                     '{\n'
-                     '    return explicit_%s;\n'
-                     '}' % (qual, decl, proto.c_call()))
-            return "".join(funcs)
-        if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]:
-            create_func = True
-            last_param_index = -1 # For create funcs don't care if last param is ndo
-        if True in [destroy_txt in proto.name for destroy_txt in ['Destroy', 'Free']]:
-            destroy_obj_type = proto.params[-2].ty
-            if destroy_obj_type in vulkan.object_non_dispatch_list:
-                destroy_func = True
-
-        # First thing we need to do is gather uses of non-dispatchable-objects (ndos)
-        (struct_uses, local_decls) = get_object_uses(vulkan.object_non_dispatch_list, proto.params[1:last_param_index])
-
-        dispatch_param = proto.params[0].name
-        if 'CreateInstance' in proto.name:
-           dispatch_param = '*' + proto.params[1].name
-        pre_call_txt += '%slayer_data *my_map_data = get_my_data_ptr(get_dispatch_key(%s), layer_data_map);\n' % (indent, dispatch_param)
-        if len(struct_uses) > 0:
-            pre_call_txt += '// STRUCT USES:%s\n' % sorted(struct_uses)
-            if len(local_decls) > 0:
-                pre_call_txt += '//LOCAL DECLS:%s\n' % sorted(local_decls)
-            if destroy_func: # only one object
-                pre_call_txt += '%sstd::unique_lock<std::mutex> lock(global_lock);\n' % (indent)
-                for del_obj in sorted(struct_uses):
-                    pre_call_txt += '%suint64_t local_%s = reinterpret_cast<uint64_t &>(%s);\n' % (indent, del_obj, del_obj)
-                    pre_call_txt += '%s%s = (%s)my_map_data->unique_id_mapping[local_%s];\n' % (indent, del_obj, struct_uses[del_obj], del_obj)
-                pre_call_txt += '%smy_map_data->unique_id_mapping.erase(local_%s);\n' % (indent, proto.params[-2].name)
-                pre_call_txt += '%slock.unlock();\n' % (indent)
-                (pre_decl, pre_code, post_code) = ('', '', '')
-            else:
-                (pre_decl, pre_code, post_code) = self._gen_obj_code(struct_uses, local_decls, '    ', '', 0, set(), True)
-            # This is a bit hacky but works for now. Need to decl local versions of top-level structs
-            for ld in sorted(local_decls):
-                init_null_txt = 'NULL';
-                if '*' not in local_decls[ld]:
-                    init_null_txt = '{}';
-                if local_decls[ld].strip('*') not in vulkan.object_non_dispatch_list:
-                    pre_decl += '    safe_%s local_%s = %s;\n' % (local_decls[ld], ld, init_null_txt)
-            if pre_code != '': # lock around map uses
-                pre_code = '%s{\n%sstd::lock_guard<std::mutex> lock(global_lock);\n%s%s}\n' % (indent, indent, pre_code, indent)
-            pre_call_txt += '%s%s' % (pre_decl, pre_code)
-            post_call_txt += '%s' % (post_code)
-        elif create_func:
-            base_type = proto.params[-1].ty.replace('const ', '').strip('*')
-            if base_type not in vulkan.object_non_dispatch_list:
-                return None
-        else:
-            return None
-
-        ret_val = ''
-        ret_stmt = ''
-        if proto.ret != "void":
-            ret_val = "%s result = " % proto.ret
-            ret_stmt = "    return result;\n"
-        if create_func:
-            obj_type = proto.params[-1].ty.strip('*')
-            obj_name = proto.params[-1].name
-            if obj_type in vulkan.object_non_dispatch_list:
-                local_name = "unique%s" % obj_type[2:]
-                post_call_txt += '%sif (VK_SUCCESS == result) {\n' % (indent)
-                indent += '    '
-                post_call_txt += '%sstd::lock_guard<std::mutex> lock(global_lock);\n' % (indent)
-                if obj_name in custom_create_dict:
-                    post_call_txt += '%s\n' % (self.lineinfo.get())
-                    local_name = '%ss' % (local_name) # add 's' to end for vector of many
-                    post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, custom_create_dict[obj_name])
-                    indent += '    '
-                    post_call_txt += '%suint64_t unique_id = global_unique_id++;\n' % (indent)
-                    post_call_txt += '%smy_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(%s[i]);\n' % (indent, obj_name)
-                    post_call_txt += '%s%s[i] = reinterpret_cast<%s&>(unique_id);\n' % (indent, obj_name, obj_type)
-                    indent = indent[4:]
-                    post_call_txt += '%s}\n' % (indent)
-                else:
-                    post_call_txt += '%s\n' % (self.lineinfo.get())
-                    post_call_txt += '%suint64_t unique_id = global_unique_id++;\n' % (indent)
-                    post_call_txt += '%smy_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*%s);\n' % (indent, obj_name)
-                    post_call_txt += '%s*%s = reinterpret_cast<%s&>(unique_id);\n' % (indent, obj_name, obj_type)
-                indent = indent[4:]
-                post_call_txt += '%s}\n' % (indent)
-
-        call_sig = proto.c_call()
-        # Replace default params with any custom local params
-        for ld in local_decls:
-            const_qualifier = ''
-            for p in proto.params:
-                if ld == p.name and 'const' in p.ty:
-                    const_qualifier = 'const'
-            call_sig = call_sig.replace(ld, '(%s %s)local_%s' % (const_qualifier, local_decls[ld], ld))
-        if proto_is_global(proto):
-            table_type = "instance"
-        else:
-            table_type = "device"
-        pre_call_txt += '%s\n' % (self.lineinfo.get())
-        open_ifdef = ''
-        close_ifdef = ''
-        if proto.name in ifdef_dict:
-            open_ifdef = '#ifdef %s\n' % (ifdef_dict[proto.name])
-            close_ifdef = '#endif\n'
-        funcs.append('%s'
-                     '%s%s\n'
-                     '{\n'
-                     '%s'
-                     '    %sget_dispatch_table(unique_objects_%s_table_map, %s)->%s;\n'
-                     '%s'
-                     '%s'
-                     '}\n'
-                     '%s' % (open_ifdef, qual, decl, pre_call_txt, ret_val, table_type, dispatch_param, call_sig, post_call_txt, ret_stmt, close_ifdef))
-        return "\n\n".join(funcs)
-
-    def generate_body(self):
-        self.layer_name = "unique_objects"
-        extensions=[('wsi_enabled',
-                     ['vkCreateSwapchainKHR',
-                      'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR',
-                      'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])]
-        surface_wsi_instance_exts = [
-                      'vkDestroySurfaceKHR',
-                      'vkGetPhysicalDeviceSurfaceSupportKHR',
-                      'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
-                      'vkGetPhysicalDeviceSurfaceFormatsKHR',
-                      'vkGetPhysicalDeviceSurfacePresentModesKHR']
-        display_wsi_instance_exts = [
-                      'vkGetPhysicalDeviceDisplayPropertiesKHR',
-                      'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
-                      'vkGetDisplayPlaneSupportedDisplaysKHR',
-                      'vkGetDisplayModePropertiesKHR',
-                      'vkCreateDisplayModeKHR',
-                      'vkGetDisplayPlaneCapabilitiesKHR',
-                      'vkCreateDisplayPlaneSurfaceKHR']
-        if self.wsi == 'Win32':
-            instance_extensions=[('wsi_enabled', surface_wsi_instance_exts),
-                                 ('display_enabled', display_wsi_instance_exts),
-                                 ('win32_enabled', ['vkCreateWin32SurfaceKHR'])]
-        elif self.wsi == 'Android':
-            instance_extensions=[('wsi_enabled', surface_wsi_instance_exts),
-                                 ('android_enabled', ['vkCreateAndroidSurfaceKHR'])]
-        elif self.wsi == 'Xcb' or self.wsi == 'Xlib' or self.wsi == 'Wayland' or self.wsi == 'Mir':
-            instance_extensions=[('wsi_enabled', surface_wsi_instance_exts),
-                                 ('display_enabled', display_wsi_instance_exts),
-                                 ('xcb_enabled', ['vkCreateXcbSurfaceKHR']),
-                                 ('xlib_enabled', ['vkCreateXlibSurfaceKHR']),
-                                 ('wayland_enabled',  ['vkCreateWaylandSurfaceKHR']),
-                                 ('mir_enabled', ['vkCreateMirSurfaceKHR'])]
-        elif self.wsi == 'Display':
-            instance_extensions=[('wsi_enabled', surface_wsi_instance_exts),
-                                 ('display_enabled', display_wsi_instance_exts)]
-        else:
-            print('Error: Undefined DisplayServer')
-            instance_extensions=[]
-
-        body = ["namespace %s {" % self.layer_name,
-                self._generate_dispatch_entrypoints(),
-                self._generate_layer_introspection_function(),
-                self._generate_layer_gpa_function(extensions,
-                                                  instance_extensions),
-                "} // namespace %s" % self.layer_name,
-                self._gen_layer_interface_v0_functions()]
-        return "\n\n".join(body)
-
-def main():
-    wsi = {
-            "Win32",
-            "Android",
-            "Xcb",
-            "Xlib",
-            "Wayland",
-            "Mir",
-            "Display",
-    }
-
-    subcommands = {
-            "unique_objects" : UniqueObjectsSubcommand,
-    }
-
-    if len(sys.argv) < 4 or sys.argv[1] not in wsi or sys.argv[2] not in subcommands or not os.path.exists(sys.argv[3]):
-        print("Usage: %s <wsi> <subcommand> <input_header> [outdir]" % sys.argv[0])
-        print
-        print("Available subcommands are: %s" % " ".join(subcommands))
-        exit(1)
-
-    hfp = vk_helper.HeaderFileParser(sys.argv[3])
-    hfp.parse()
-    vk_helper.enum_val_dict = hfp.get_enum_val_dict()
-    vk_helper.enum_type_dict = hfp.get_enum_type_dict()
-    vk_helper.struct_dict = hfp.get_struct_dict()
-    vk_helper.typedef_fwd_dict = hfp.get_typedef_fwd_dict()
-    vk_helper.typedef_rev_dict = hfp.get_typedef_rev_dict()
-    vk_helper.types_dict = hfp.get_types_dict()
-
-    outfile = None
-    if len(sys.argv) >= 5:
-        outfile = sys.argv[4]
-
-    subcmd = subcommands[sys.argv[2]](outfile)
-    subcmd.run()
-
-if __name__ == "__main__":
-    main()