Home | History | Annotate | Download | only in vulkan-validation-layers
      1 #!/usr/bin/env python3
      2 #
      3 # VK
      4 #
      5 # Copyright (c) 2015-2016 The Khronos Group Inc.
      6 # Copyright (c) 2015-2016 Valve Corporation
      7 # Copyright (c) 2015-2016 LunarG, Inc.
      8 # Copyright (c) 2015-2016 Google Inc.
      9 #
     10 # Permission is hereby granted, free of charge, to any person obtaining a copy
     11 # of this software and/or associated documentation files (the "Materials"), to
     12 # deal in the Materials without restriction, including without limitation the
     13 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     14 # sell copies of the Materials, and to permit persons to whom the Materials
     15 # are furnished to do so, subject to the following conditions:
     16 #
     17 # The above copyright notice(s) and this permission notice shall be included
     18 # in all copies or substantial portions of the Materials.
     19 #
     20 # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23 #
     24 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     25 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     26 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     27 # USE OR OTHER DEALINGS IN THE MATERIALS
     28 #
     29 # Author: Tobin Ehlis <tobine (at] google.com>
     30 # Author: Courtney Goeltzenleuchter <courtneygo (at] google.com>
     31 # Author: Jon Ashburn <jon (at] lunarg.com>
     32 # Author: Mark Lobodzinski <mark (at] lunarg.com>
     33 # Author: Mike Stroyan <stroyan (at] google.com>
     34 # Author: Tony Barbour <tony (at] LunarG.com>
     35 # Author: Chia-I Wu <olv (at] google.com>
     36 # Author: Gwan-gyeong Mun <kk.moon (at] samsung.com>
     37 
     38 import sys
     39 import os
     40 import re
     41 
     42 import vulkan
     43 import vk_helper
     44 from source_line_info import sourcelineinfo
     45 from collections import defaultdict
     46 
     47 def proto_is_global(proto):
     48     global_function_names = [
     49         "CreateInstance",
     50         "EnumerateInstanceLayerProperties",
     51         "EnumerateInstanceExtensionProperties",
     52         "EnumerateDeviceLayerProperties",
     53         "EnumerateDeviceExtensionProperties",
     54         "CreateXcbSurfaceKHR",
     55         "GetPhysicalDeviceXcbPresentationSupportKHR",
     56         "CreateXlibSurfaceKHR",
     57         "GetPhysicalDeviceXlibPresentationSupportKHR",
     58         "CreateWaylandSurfaceKHR",
     59         "GetPhysicalDeviceWaylandPresentationSupportKHR",
     60         "CreateMirSurfaceKHR",
     61         "GetPhysicalDeviceMirPresentationSupportKHR",
     62         "CreateAndroidSurfaceKHR",
     63         "CreateWin32SurfaceKHR",
     64         "GetPhysicalDeviceWin32PresentationSupportKHR"
     65     ]
     66     if proto.params[0].ty == "VkInstance" or proto.params[0].ty == "VkPhysicalDevice" or proto.name in global_function_names:
     67        return True
     68     else:
     69        return False
     70 
     71 def wsi_name(ext_name):
     72     wsi_prefix = ""
     73     if 'Xcb' in ext_name:
     74         wsi_prefix = 'XCB'
     75     elif 'Xlib' in ext_name:
     76         wsi_prefix = 'XLIB'
     77     elif 'Win32' in ext_name:
     78         wsi_prefix = 'WIN32'
     79     elif 'Mir' in ext_name:
     80         wsi_prefix = 'MIR'
     81     elif 'Wayland' in ext_name:
     82         wsi_prefix = 'WAYLAND'
     83     elif 'Android' in ext_name:
     84         wsi_prefix = 'ANDROID'
     85     else:
     86         wsi_prefix = ''
     87     return wsi_prefix
     88 
     89 def wsi_ifdef(ext_name):
     90     wsi_prefix = wsi_name(ext_name)
     91     if not wsi_prefix:
     92         return ''
     93     else:
     94         return "#ifdef VK_USE_PLATFORM_%s_KHR" % wsi_prefix
     95 
     96 def wsi_endif(ext_name):
     97     wsi_prefix = wsi_name(ext_name)
     98     if not wsi_prefix:
     99         return ''
    100     else:
    101         return "#endif  // VK_USE_PLATFORM_%s_KHR" % wsi_prefix
    102 
    103 def generate_get_proc_addr_check(name):
    104     return "    if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
    105            "        return NULL;" % ((name,) * 3)
    106 
    107 def ucc_to_U_C_C(CamelCase):
    108     temp = re.sub('(.)([A-Z][a-z]+)',  r'\1_\2', CamelCase)
    109     return re.sub('([a-z0-9])([A-Z])', r'\1_\2', temp).upper()
    110 
    111 # Parse complete struct chain and add any new ndo_uses to the dict
    112 def gather_object_uses_in_struct(obj_list, struct_type):
    113     struct_uses = {}
    114     if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict:
    115         struct_type = vk_helper.typedef_rev_dict[struct_type]
    116         # Parse elements of this struct param to identify objects and/or arrays of objects
    117         for m in sorted(vk_helper.struct_dict[struct_type]):
    118             array_len = "%s" % (str(vk_helper.struct_dict[struct_type][m]['array_size']))
    119             base_type = vk_helper.struct_dict[struct_type][m]['type']
    120             mem_name = vk_helper.struct_dict[struct_type][m]['name']
    121             if array_len != '0':
    122                 mem_name = "%s[%s]" % (mem_name, array_len)
    123             if base_type in obj_list:
    124                 #if array_len not in ndo_uses:
    125                 #    struct_uses[array_len] = []
    126                 #struct_uses[array_len].append("%s%s,%s" % (name_prefix, struct_name, base_type))
    127                 struct_uses[mem_name] = base_type
    128             elif vk_helper.is_type(base_type, 'struct'):
    129                 sub_uses = gather_object_uses_in_struct(obj_list, base_type)
    130                 if len(sub_uses) > 0:
    131                     struct_uses[mem_name] = sub_uses
    132     return struct_uses
    133 
    134 # For the given list of object types, Parse the given list of params
    135 #  and return dict of params that use one of the obj_list types
    136 # Format of the dict is that terminal elements have <name>,<type>
    137 #  non-terminal elements will have <name>[<array_size>]
    138 # TODO : This analysis could be done up-front at vk_helper time
    139 def get_object_uses(obj_list, params):
    140     obj_uses = {}
    141     local_decls = {}
    142     param_count = 'NONE' # track params that give array sizes
    143     for p in params:
    144         base_type = p.ty.replace('const ', '').strip('*')
    145         array_len = ''
    146         is_ptr = False
    147         if 'count' in p.name.lower():
    148             param_count = p.name
    149         ptr_txt = ''
    150         if '*' in p.ty:
    151             is_ptr = True
    152             ptr_txt = '*'
    153         if base_type in obj_list:
    154             if is_ptr and 'const' in p.ty and param_count != 'NONE':
    155                 array_len = "[%s]" % param_count
    156                 # Non-arrays we can overwrite in place, but need local decl for arrays
    157                 local_decls[p.name] = '%s%s' % (base_type, ptr_txt)
    158             #if array_len not in obj_uses:
    159             #    obj_uses[array_len] = {}
    160             # obj_uses[array_len][p.name] = base_type
    161             obj_uses["%s%s" % (p.name, array_len)] = base_type
    162         elif vk_helper.is_type(base_type, 'struct'):
    163             struct_name = p.name
    164             if 'NONE' != param_count:
    165                 struct_name = "%s[%s]" % (struct_name, param_count)
    166             struct_uses = gather_object_uses_in_struct(obj_list, base_type)
    167             if len(struct_uses) > 0:
    168                 obj_uses[struct_name] = struct_uses
    169                 # This is a top-level struct w/ uses below it, so need local decl
    170                 local_decls['%s' % (p.name)] = '%s%s' % (base_type, ptr_txt)
    171     return (obj_uses, local_decls)
    172 
    173 class Subcommand(object):
    174     def __init__(self, argv):
    175         self.argv = argv
    176         self.headers = vulkan.headers
    177         self.protos = vulkan.protos
    178         self.no_addr = False
    179         self.layer_name = ""
    180         self.lineinfo = sourcelineinfo()
    181         self.wsi = sys.argv[1]
    182 
    183     def run(self):
    184         print(self.generate())
    185 
    186     def generate(self):
    187         copyright = self.generate_copyright()
    188         header = self.generate_header()
    189         body = self.generate_body()
    190         footer = self.generate_footer()
    191 
    192         contents = []
    193         if copyright:
    194             contents.append(copyright)
    195         if header:
    196             contents.append(header)
    197         if body:
    198             contents.append(body)
    199         if footer:
    200             contents.append(footer)
    201 
    202         return "\n\n".join(contents)
    203 
    204     def generate_copyright(self):
    205         return """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
    206 
    207 /*
    208  * Copyright (c) 2015-2016 The Khronos Group Inc.
    209  * Copyright (c) 2015-2016 Valve Corporation
    210  * Copyright (c) 2015-2016 LunarG, Inc.
    211  * Copyright (c) 2015 Google, Inc.
    212  *
    213  * Permission is hereby granted, free of charge, to any person obtaining a copy
    214  * of this software and/or associated documentation files (the "Materials"), to
    215  * deal in the Materials without restriction, including without limitation the
    216  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    217  * sell copies of the Materials, and to permit persons to whom the Materials
    218  * are furnished to do so, subject to the following conditions:
    219  *
    220  * The above copyright notice(s) and this permission notice shall be included
    221  * in all copies or substantial portions of the Materials.
    222  *
    223  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    224  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    225  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    226  *
    227  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    228  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    229  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
    230  * USE OR OTHER DEALINGS IN THE MATERIALS
    231  *
    232  * Author: Tobin Ehlis <tobine (at] google.com>
    233  * Author: Courtney Goeltzenleuchter <courtneygo (at] google.com>
    234  * Author: Jon Ashburn <jon (at] lunarg.com>
    235  * Author: Mark Lobodzinski <mark (at] lunarg.com>
    236  * Author: Mike Stroyan <stroyan (at] google.com>
    237  * Author: Tony Barbour <tony (at] LunarG.com>
    238  */"""
    239 
    240     def generate_header(self):
    241         return "\n".join(["#include <" + h + ">" for h in self.headers])
    242 
    243     def generate_body(self):
    244         pass
    245 
    246     def generate_footer(self):
    247         pass
    248 
    249     # Return set of printf '%' qualifier and input to that qualifier
    250     def _get_printf_params(self, vk_type, name, output_param, cpp=False):
    251         # TODO : Need ENUM and STRUCT checks here
    252         if vk_helper.is_type(vk_type, 'enum'):#"_TYPE" in vk_type: # TODO : This should be generic ENUM check
    253             return ("%s", "string_%s(%s)" % (vk_type.replace('const ', '').strip('*'), name))
    254         if "char*" == vk_type:
    255             return ("%s", name)
    256         if "uint64" in vk_type:
    257             if '*' in vk_type:
    258                 return ("%lu", "*%s" % name)
    259             return ("%lu", name)
    260         if vk_type.strip('*') in vulkan.object_non_dispatch_list:
    261             if '*' in vk_type:
    262                 return ("%lu", "%s" % name)
    263             return ("%lu", "%s" % name)
    264         if "size" in vk_type:
    265             if '*' in vk_type:
    266                 return ("%lu", "(unsigned long)*%s" % name)
    267             return ("%lu", "(unsigned long)%s" % name)
    268         if "float" in vk_type:
    269             if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
    270                 if cpp:
    271                     return ("[%i, %i, %i, %i]", '"[" << %s[0] << "," << %s[1] << "," << %s[2] << "," << %s[3] << "]"' % (name, name, name, name))
    272                 return ("[%f, %f, %f, %f]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
    273             return ("%f", name)
    274         if "bool" in vk_type.lower() or 'xcb_randr_crtc_t' in vk_type:
    275             return ("%u", name)
    276         if True in [t in vk_type.lower() for t in ["int", "flags", "mask", "xcb_window_t"]]:
    277             if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
    278                 if cpp:
    279                     return ("[%i, %i, %i, %i]", "%s[0] << %s[1] << %s[2] << %s[3]" % (name, name, name, name))
    280                 return ("[%i, %i, %i, %i]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
    281             if '*' in vk_type:
    282                 if 'pUserData' == name:
    283                     return ("%i", "((pUserData == 0) ? 0 : *(pUserData))")
    284                 if 'const' in vk_type.lower():
    285                     return ("%p", "(void*)(%s)" % name)
    286                 return ("%i", "*(%s)" % name)
    287             return ("%i", name)
    288         # TODO : This is special-cased as there's only one "format" param currently and it's nice to expand it
    289         if "VkFormat" == vk_type:
    290             if cpp:
    291                 return ("%p", "&%s" % name)
    292             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))
    293         if output_param:
    294             return ("%p", "(void*)*%s" % name)
    295         if vk_helper.is_type(vk_type, 'struct') and '*' not in vk_type:
    296             return ("%p", "(void*)(&%s)" % name)
    297         return ("%p", "(void*)(%s)" % name)
    298 
    299     def _gen_create_msg_callback(self):
    300         r_body = []
    301         r_body.append('%s' % self.lineinfo.get())
    302         r_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(')
    303         r_body.append('        VkInstance                                   instance,')
    304         r_body.append('        const VkDebugReportCallbackCreateInfoEXT*    pCreateInfo,')
    305         r_body.append('        const VkAllocationCallbacks*                 pAllocator,')
    306         r_body.append('        VkDebugReportCallbackEXT*                    pCallback)')
    307         r_body.append('{')
    308         # Switch to this code section for the new per-instance storage and debug callbacks
    309         if self.layer_name in ['object_tracker', 'unique_objects']:
    310             r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name )
    311             r_body.append('    VkResult result = pInstanceTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);')
    312             r_body.append('    if (VK_SUCCESS == result) {')
    313             r_body.append('        layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
    314             r_body.append('        result = layer_create_msg_callback(my_data->report_data,')
    315             r_body.append('                                           pCreateInfo,')
    316             r_body.append('                                           pAllocator,')
    317             r_body.append('                                           pCallback);')
    318             r_body.append('    }')
    319             r_body.append('    return result;')
    320         else:
    321             r_body.append('    VkResult result = instance_dispatch_table(instance)->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);')
    322             r_body.append('    if (VK_SUCCESS == result) {')
    323             r_body.append('        layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
    324             r_body.append('        result = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pCallback);')
    325             r_body.append('    }')
    326             r_body.append('    return result;')
    327         r_body.append('}')
    328         return "\n".join(r_body)
    329 
    330     def _gen_destroy_msg_callback(self):
    331         r_body = []
    332         r_body.append('%s' % self.lineinfo.get())
    333         r_body.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, const VkAllocationCallbacks *pAllocator)')
    334         r_body.append('{')
    335         # Switch to this code section for the new per-instance storage and debug callbacks
    336         if self.layer_name in ['object_tracker', 'unique_objects']:
    337             r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name )
    338         else:
    339             r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);')
    340         r_body.append('    pInstanceTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);')
    341         r_body.append('    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);')
    342         r_body.append('    layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);')
    343         r_body.append('}')
    344         return "\n".join(r_body)
    345 
    346     def _gen_debug_report_msg(self):
    347         r_body = []
    348         r_body.append('%s' % self.lineinfo.get())
    349         r_body.append('VK_LAYER_EXPORT 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)')
    350         r_body.append('{')
    351         # Switch to this code section for the new per-instance storage and debug callbacks
    352         if self.layer_name == 'object_tracker':
    353             r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name )
    354         else:
    355             r_body.append('    VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);')
    356         r_body.append('    pInstanceTable->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);')
    357         r_body.append('}')
    358         return "\n".join(r_body)
    359 
    360     def _gen_layer_get_global_extension_props(self, layer="object_tracker"):
    361         ggep_body = []
    362         # generated layers do not provide any global extensions
    363         ggep_body.append('%s' % self.lineinfo.get())
    364 
    365         ggep_body.append('')
    366         if self.layer_name == 'object_tracker':
    367             ggep_body.append('static const VkExtensionProperties instance_extensions[] = {')
    368             ggep_body.append('    {')
    369             ggep_body.append('        VK_EXT_DEBUG_REPORT_EXTENSION_NAME,')
    370             ggep_body.append('        VK_EXT_DEBUG_REPORT_SPEC_VERSION')
    371             ggep_body.append('    }')
    372             ggep_body.append('};')
    373         ggep_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,  VkExtensionProperties* pProperties)')
    374         ggep_body.append('{')
    375         if self.layer_name == 'object_tracker':
    376           ggep_body.append('    return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);')
    377         else:
    378           ggep_body.append('    return util_GetExtensionProperties(0, NULL, pCount, pProperties);')
    379         ggep_body.append('}')
    380         return "\n".join(ggep_body)
    381 
    382     def _gen_layer_get_global_layer_props(self, layer="object_tracker"):
    383         ggep_body = []
    384         layer_name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', layer)
    385         layer_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', layer_name).lower()
    386         ggep_body.append('%s' % self.lineinfo.get())
    387         ggep_body.append('static const VkLayerProperties globalLayerProps[] = {')
    388         ggep_body.append('    {')
    389         if self.layer_name in ['unique_objects']:
    390           ggep_body.append('        "VK_LAYER_GOOGLE_%s",' % layer)
    391           ggep_body.append('        VK_LAYER_API_VERSION, // specVersion')
    392           ggep_body.append('        1, // implementationVersion')
    393           ggep_body.append('        "Google Validation Layer"')
    394         else:
    395           ggep_body.append('        "VK_LAYER_LUNARG_%s",' % layer)
    396           ggep_body.append('        VK_LAYER_API_VERSION, // specVersion')
    397           ggep_body.append('        1, // implementationVersion')
    398           ggep_body.append('        "LunarG Validation Layer"')
    399         ggep_body.append('    }')
    400         ggep_body.append('};')
    401         ggep_body.append('')
    402         ggep_body.append('%s' % self.lineinfo.get())
    403         ggep_body.append('')
    404         ggep_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,  VkLayerProperties* pProperties)')
    405         ggep_body.append('{')
    406         ggep_body.append('    return util_GetLayerProperties(ARRAY_SIZE(globalLayerProps), globalLayerProps, pCount, pProperties);')
    407         ggep_body.append('}')
    408         return "\n".join(ggep_body)
    409 
    410     def _gen_layer_get_physical_device_layer_props(self, layer="object_tracker"):
    411         gpdlp_body = []
    412         gpdlp_body.append('%s' % self.lineinfo.get())
    413         gpdlp_body.append('static const VkLayerProperties deviceLayerProps[] = {')
    414         gpdlp_body.append('    {')
    415         if self.layer_name in ['unique_objects']:
    416           gpdlp_body.append('        "VK_LAYER_GOOGLE_%s",' % layer)
    417           gpdlp_body.append('        VK_LAYER_API_VERSION, // specVersion')
    418           gpdlp_body.append('        1, // implementationVersion')
    419           gpdlp_body.append('        "Google Validation Layer"')
    420         else:
    421           gpdlp_body.append('        "VK_LAYER_LUNARG_%s",' % layer)
    422           gpdlp_body.append('        VK_LAYER_API_VERSION, // specVersion')
    423           gpdlp_body.append('        1, // implementationVersion')
    424           gpdlp_body.append('        "LunarG Validation Layer"')
    425         gpdlp_body.append('    }')
    426         gpdlp_body.append('};')
    427         gpdlp_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties* pProperties)')
    428         gpdlp_body.append('{')
    429         gpdlp_body.append('    return util_GetLayerProperties(ARRAY_SIZE(deviceLayerProps), deviceLayerProps, pCount, pProperties);')
    430         gpdlp_body.append('}')
    431         gpdlp_body.append('')
    432         return "\n".join(gpdlp_body)
    433 
    434     def _generate_dispatch_entrypoints(self, qual=""):
    435         if qual:
    436             qual += " "
    437 
    438         funcs = []
    439         intercepted = []
    440         for proto in self.protos:
    441             if proto.name == "GetDeviceProcAddr" or proto.name == "GetInstanceProcAddr":
    442                 continue
    443             else:
    444                 intercept = self.generate_intercept(proto, qual)
    445                 if intercept is None:
    446                     # fill in default intercept for certain entrypoints
    447                     if 'CreateDebugReportCallbackEXT' == proto.name:
    448                         intercept = self._gen_layer_dbg_create_msg_callback()
    449                     elif 'DestroyDebugReportCallbackEXT' == proto.name:
    450                         intercept = self._gen_layer_dbg_destroy_msg_callback()
    451                     elif 'DebugReportMessageEXT' == proto.name:
    452                         intercept = self._gen_debug_report_msg()
    453                     elif 'CreateDevice' == proto.name:
    454                         funcs.append('/* CreateDevice HERE */')
    455                     elif 'EnumerateInstanceExtensionProperties' == proto.name:
    456                         intercept = self._gen_layer_get_global_extension_props(self.layer_name)
    457                     elif 'EnumerateInstanceLayerProperties' == proto.name:
    458                         intercept = self._gen_layer_get_global_layer_props(self.layer_name)
    459                     elif 'EnumerateDeviceLayerProperties' == proto.name:
    460                         intercept = self._gen_layer_get_physical_device_layer_props(self.layer_name)
    461 
    462                 if intercept is not None:
    463                     funcs.append(intercept)
    464                     if not "KHR" in proto.name:
    465                         intercepted.append(proto)
    466 
    467         prefix="vk"
    468         lookups = []
    469         for proto in intercepted:
    470             lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
    471             lookups.append("    return (PFN_vkVoidFunction) %s%s;" %
    472                     (prefix, proto.name))
    473 
    474         # add customized layer_intercept_proc
    475         body = []
    476         body.append('%s' % self.lineinfo.get())
    477         body.append("static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)")
    478         body.append("{")
    479         body.append(generate_get_proc_addr_check("name"))
    480         body.append("")
    481         body.append("    name += 2;")
    482         body.append("    %s" % "\n    ".join(lookups))
    483         body.append("")
    484         body.append("    return NULL;")
    485         body.append("}")
    486         # add layer_intercept_instance_proc
    487         lookups = []
    488         for proto in self.protos:
    489             if not proto_is_global(proto):
    490                 continue
    491 
    492             if not proto in intercepted:
    493                 continue
    494             if proto.name == "CreateInstance":
    495                 continue
    496             if proto.name == "CreateDevice":
    497                 continue
    498             lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
    499             lookups.append("    return (PFN_vkVoidFunction) %s%s;" % (prefix, proto.name))
    500 
    501         body.append("static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)")
    502         body.append("{")
    503         body.append(generate_get_proc_addr_check("name"))
    504         body.append("")
    505         body.append("    name += 2;")
    506         body.append("    %s" % "\n    ".join(lookups))
    507         body.append("")
    508         body.append("    return NULL;")
    509         body.append("}")
    510 
    511         funcs.append("\n".join(body))
    512         return "\n\n".join(funcs)
    513 
    514     def _generate_extensions(self):
    515         exts = []
    516         exts.append('%s' % self.lineinfo.get())
    517         exts.append(self._gen_create_msg_callback())
    518         exts.append(self._gen_destroy_msg_callback())
    519         exts.append(self._gen_debug_report_msg())
    520         return "\n".join(exts)
    521 
    522     def _generate_layer_gpa_function(self, extensions=[], instance_extensions=[]):
    523         func_body = []
    524 #
    525 # New style of GPA Functions for the new layer_data/layer_logging changes
    526 #
    527         if self.layer_name in ['object_tracker', 'unique_objects']:
    528             func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n"
    529                              "{\n"
    530                              "    PFN_vkVoidFunction addr;\n"
    531                              "    if (!strcmp(\"vkGetDeviceProcAddr\", funcName)) {\n"
    532                              "        return (PFN_vkVoidFunction) vkGetDeviceProcAddr;\n"
    533                              "    }\n\n"
    534                              "    addr = layer_intercept_proc(funcName);\n"
    535                              "    if (addr)\n"
    536                              "        return addr;\n"
    537                              "    if (device == VK_NULL_HANDLE) {\n"
    538                              "        return NULL;\n"
    539                              "    }\n")
    540             if 0 != len(extensions):
    541                 func_body.append('%s' % self.lineinfo.get())
    542                 func_body.append('    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);')
    543                 for (ext_enable, ext_list) in extensions:
    544                     extra_space = ""
    545                     if 0 != len(ext_enable):
    546                         func_body.append('    if (my_device_data->%s) {' % ext_enable)
    547                         extra_space = "    "
    548                     for ext_name in ext_list:
    549                         func_body.append('    %sif (!strcmp("%s", funcName))\n'
    550                                          '        %sreturn reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, extra_space, ext_name))
    551                     if 0 != len(ext_enable):
    552                         func_body.append('    }\n')
    553             func_body.append("\n    if (get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr == NULL)\n"
    554                              "        return NULL;\n"
    555                              "    return get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr(device, funcName);\n"
    556                              "}\n" % (self.layer_name, self.layer_name))
    557             func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)\n"
    558                              "{\n"
    559                              "    PFN_vkVoidFunction addr;\n"
    560                              "    if (!strcmp(funcName, \"vkGetInstanceProcAddr\"))\n"
    561                              "        return (PFN_vkVoidFunction) vkGetInstanceProcAddr;\n"
    562                              "    if (!strcmp(funcName, \"vkCreateInstance\"))\n"
    563                              "        return (PFN_vkVoidFunction) vkCreateInstance;\n"
    564                              "    if (!strcmp(funcName, \"vkCreateDevice\"))\n"
    565                              "        return (PFN_vkVoidFunction) vkCreateDevice;\n"
    566                              "    addr = layer_intercept_instance_proc(funcName);\n"
    567                              "    if (addr) {\n"
    568                              "        return addr;"
    569                              "    }\n"
    570                              "    if (instance == VK_NULL_HANDLE) {\n"
    571                              "        return NULL;\n"
    572                              "    }\n"
    573                              )
    574 
    575             table_declared = False
    576             if 0 != len(instance_extensions):
    577                 for (ext_enable, ext_list) in instance_extensions:
    578                     extra_space = ""
    579                     if 0 != len(ext_enable):
    580                         if ext_enable == 'msg_callback_get_proc_addr':
    581                             func_body.append("    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n"
    582                                      "    addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);\n"
    583                                      "    if (addr) {\n"
    584                                      "        return addr;\n"
    585                                      "    }\n")
    586                         else:
    587                             if table_declared == False:
    588                                 func_body.append("    VkLayerInstanceDispatchTable* pTable = get_dispatch_table(%s_instance_table_map, instance);" % self.layer_name)
    589                                 table_declared = True
    590                             func_body.append('    if (instanceExtMap.size() != 0 && instanceExtMap[pTable].%s)' % ext_enable)
    591                             func_body.append('    {')
    592                             extra_space = "    "
    593                             for ext_name in ext_list:
    594                                 if wsi_name(ext_name):
    595                                     func_body.append('%s' % wsi_ifdef(ext_name))
    596                                 func_body.append('    %sif (!strcmp("%s", funcName))\n'
    597                                                  '            return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name))
    598                                 if wsi_name(ext_name):
    599                                     func_body.append('%s' % wsi_endif(ext_name))
    600                             if 0 != len(ext_enable):
    601                                func_body.append('    }\n')
    602 
    603             func_body.append("    if (get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr == NULL) {\n"
    604                              "        return NULL;\n"
    605                              "    }\n"
    606                              "    return get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);\n"
    607                              "}\n" % (self.layer_name, self.layer_name))
    608             return "\n".join(func_body)
    609         else:
    610             func_body.append('%s' % self.lineinfo.get())
    611             func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n"
    612                              "{\n"
    613                              "    PFN_vkVoidFunction addr;\n")
    614             func_body.append("\n"
    615                              "    loader_platform_thread_once(&initOnce, init%s);\n\n"
    616                              "    if (!strcmp(\"vkGetDeviceProcAddr\", funcName)) {\n"
    617                              "        return (PFN_vkVoidFunction) vkGetDeviceProcAddr;\n"
    618                              "    }\n\n"
    619                              "    addr = layer_intercept_proc(funcName);\n"
    620                              "    if (addr)\n"
    621                              "        return addr;" % self.layer_name)
    622             func_body.append("    if (device == VK_NULL_HANDLE) {\n"
    623                              "        return NULL;\n"
    624                              "    }\n")
    625             func_body.append('')
    626             func_body.append('    VkLayerDispatchTable *pDisp =  device_dispatch_table(device);')
    627             if 0 != len(extensions):
    628                 extra_space = ""
    629                 for (ext_enable, ext_list) in extensions:
    630                     if 0 != len(ext_enable):
    631                         func_body.append('    if (deviceExtMap.size() != 0 && deviceExtMap[pDisp].%s)' % ext_enable)
    632                         func_body.append('    {')
    633                         extra_space = "    "
    634                     for ext_name in ext_list:
    635                         func_body.append('    %sif (!strcmp("%s", funcName))\n'
    636                                          '            return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name))
    637                     if 0 != len(ext_enable):
    638                         func_body.append('    }')
    639             func_body.append('%s' % self.lineinfo.get())
    640             func_body.append("    {\n"
    641                              "        if (pDisp->GetDeviceProcAddr == NULL)\n"
    642                              "            return NULL;\n"
    643                              "        return pDisp->GetDeviceProcAddr(device, funcName);\n"
    644                              "    }\n"
    645                              "}\n")
    646             func_body.append('%s' % self.lineinfo.get())
    647             func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)\n"
    648                              "{\n"
    649                              "    PFN_vkVoidFunction addr;\n"
    650                              "    if (!strcmp(funcName, \"vkGetInstanceProcAddr\"))\n"
    651                              "        return (PFN_vkVoidFunction) vkGetInstanceProcAddr;\n"
    652                              "    if (!strcmp(funcName, \"vkCreateInstance\"))\n"
    653                              "        return (PFN_vkVoidFunction) vkCreateInstance;\n"
    654                              "    if (!strcmp(funcName, \"vkCreateDevice\"))\n"
    655                              "        return (PFN_vkVoidFunction) vkCreateDevice;\n"
    656                              )
    657             func_body.append(
    658                              "    loader_platform_thread_once(&initOnce, init%s);\n\n"
    659                              "    addr = layer_intercept_instance_proc(funcName);\n"
    660                              "    if (addr)\n"
    661                              "        return addr;" % self.layer_name)
    662             func_body.append("    if (instance == VK_NULL_HANDLE) {\n"
    663                              "        return NULL;\n"
    664                              "    }\n")
    665             func_body.append("")
    666             func_body.append("    VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);\n")
    667             if 0 != len(instance_extensions):
    668                 extra_space = ""
    669                 for (ext_enable, ext_list) in instance_extensions:
    670                     if 0 != len(ext_enable):
    671                         if ext_enable == 'msg_callback_get_proc_addr':
    672                             func_body.append("    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n"
    673                                      "    addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);\n"
    674                                      "    if (addr) {\n"
    675                                      "        return addr;\n"
    676                                      "    }\n")
    677                         else:
    678                             func_body.append('    if (instanceExtMap.size() != 0 && instanceExtMap[pTable].%s)' % ext_enable)
    679                             func_body.append('    {')
    680                             extra_space = "    "
    681                             for ext_name in ext_list:
    682                                 if wsi_name(ext_name):
    683                                     func_body.append('%s' % wsi_ifdef(ext_name))
    684                                 func_body.append('    %sif (!strcmp("%s", funcName))\n'
    685                                          '            return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name))
    686                                 if wsi_name(ext_name):
    687                                     func_body.append('%s' % wsi_endif(ext_name))
    688                             if 0 != len(ext_enable):
    689                                 func_body.append('    }\n')
    690 
    691             func_body.append("    if (pTable->GetInstanceProcAddr == NULL)\n"
    692                              "        return NULL;\n"
    693                              "    return pTable->GetInstanceProcAddr(instance, funcName);\n"
    694                              "}\n")
    695             return "\n".join(func_body)
    696 
    697 
    698     def _generate_layer_initialization(self, init_opts=False, prefix='vk', lockname=None, condname=None):
    699         func_body = ["#include \"vk_dispatch_table_helper.h\""]
    700         func_body.append('%s' % self.lineinfo.get())
    701         func_body.append('static void init_%s(layer_data *my_data, const VkAllocationCallbacks *pAllocator)\n'
    702                          '{\n' % self.layer_name)
    703         if init_opts:
    704             func_body.append('%s' % self.lineinfo.get())
    705             func_body.append('')
    706             func_body.append('    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_%s");' % self.layer_name)
    707             func_body.append('')
    708         if lockname is not None:
    709             func_body.append('%s' % self.lineinfo.get())
    710             func_body.append("    if (!%sLockInitialized)" % lockname)
    711             func_body.append("    {")
    712             func_body.append("        // TODO/TBD: Need to delete this mutex sometime.  How???")
    713             func_body.append("        loader_platform_thread_create_mutex(&%sLock);" % lockname)
    714             if condname is not None:
    715                 func_body.append("        loader_platform_thread_init_cond(&%sCond);" % condname)
    716             func_body.append("        %sLockInitialized = 1;" % lockname)
    717             func_body.append("    }")
    718         func_body.append("}\n")
    719         func_body.append('')
    720         return "\n".join(func_body)
    721 
    722 class ObjectTrackerSubcommand(Subcommand):
    723     def generate_header(self):
    724         header_txt = []
    725         header_txt.append('%s' % self.lineinfo.get())
    726         header_txt.append('#include <stdio.h>')
    727         header_txt.append('#include <stdlib.h>')
    728         header_txt.append('#include <string.h>')
    729         header_txt.append('#include <inttypes.h>')
    730         header_txt.append('')
    731         header_txt.append('#include "vulkan/vulkan.h"')
    732         header_txt.append('#include "vk_loader_platform.h"')
    733         header_txt.append('')
    734         header_txt.append('#include <unordered_map>')
    735         header_txt.append('using namespace std;')
    736         header_txt.append('#include "vulkan/vk_layer.h"')
    737         header_txt.append('#include "vk_layer_config.h"')
    738         header_txt.append('#include "vk_layer_table.h"')
    739         header_txt.append('#include "vk_layer_data.h"')
    740         header_txt.append('#include "vk_layer_logging.h"')
    741         header_txt.append('')
    742 #       NOTE:  The non-autoGenerated code is in the object_tracker.h header file
    743         header_txt.append('#include "object_tracker.h"')
    744         header_txt.append('')
    745         return "\n".join(header_txt)
    746 
    747     def generate_maps(self):
    748         maps_txt = []
    749         for o in vulkan.object_type_list:
    750             maps_txt.append('unordered_map<uint64_t, OBJTRACK_NODE*> %sMap;' % (o))
    751         return "\n".join(maps_txt)
    752 
    753     def _gather_object_uses(self, obj_list, struct_type, obj_set):
    754     # for each member of struct_type
    755     #     add objs in obj_list to obj_set
    756     #     call self for structs
    757         for m in vk_helper.struct_dict[struct_type]:
    758             if vk_helper.struct_dict[struct_type][m]['type'] in obj_list:
    759                 obj_set.add(vk_helper.struct_dict[struct_type][m]['type'])
    760             elif vk_helper.is_type(vk_helper.struct_dict[struct_type][m]['type'], 'struct'):
    761                 obj_set = obj_set.union(self._gather_object_uses(obj_list, vk_helper.struct_dict[struct_type][m]['type'], obj_set))
    762         return obj_set
    763 
    764     def generate_procs(self):
    765         procs_txt = []
    766         # First parse through funcs and gather dict of all objects seen by each call
    767         obj_use_dict = {}
    768         proto_list = vulkan.core.protos + vulkan.ext_khr_surface.protos + vulkan.ext_khr_surface.protos + vulkan.ext_khr_win32_surface.protos + vulkan.ext_khr_device_swapchain.protos
    769         for proto in proto_list:
    770             disp_obj = proto.params[0].ty.strip('*').replace('const ', '')
    771             if disp_obj in vulkan.object_dispatch_list:
    772                 if disp_obj not in obj_use_dict:
    773                     obj_use_dict[disp_obj] = set()
    774                 for p in proto.params[1:]:
    775                     base_type = p.ty.strip('*').replace('const ', '')
    776                     if base_type in vulkan.object_type_list:
    777                         obj_use_dict[disp_obj].add(base_type)
    778                     if vk_helper.is_type(base_type, 'struct'):
    779                         obj_use_dict[disp_obj] = self._gather_object_uses(vulkan.object_type_list, base_type, obj_use_dict[disp_obj])
    780         #for do in obj_use_dict:
    781         #    print "Disp obj %s has uses for objs: %s" % (do, ', '.join(obj_use_dict[do]))
    782 
    783         for o in vulkan.object_type_list:# vulkan.core.objects:
    784             procs_txt.append('%s' % self.lineinfo.get())
    785             name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', o)
    786             name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
    787             if o in vulkan.object_dispatch_list:
    788                 procs_txt.append('static void create_%s(%s dispatchable_object, %s vkObj, VkDebugReportObjectTypeEXT objType)' % (name, o, o))
    789             else:
    790                 procs_txt.append('static void create_%s(VkDevice dispatchable_object, %s vkObj, VkDebugReportObjectTypeEXT objType)' % (name, o))
    791             procs_txt.append('{')
    792             procs_txt.append('    log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType,(uint64_t)(vkObj), __LINE__, OBJTRACK_NONE, "OBJTRACK",')
    793             procs_txt.append('        "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64 , object_track_index++, string_VkDebugReportObjectTypeEXT(objType),')
    794             procs_txt.append('        (uint64_t)(vkObj));')
    795             procs_txt.append('')
    796             procs_txt.append('    OBJTRACK_NODE* pNewObjNode = new OBJTRACK_NODE;')
    797             procs_txt.append('    pNewObjNode->belongsTo = (uint64_t)dispatchable_object;')
    798             procs_txt.append('    pNewObjNode->objType = objType;')
    799             procs_txt.append('    pNewObjNode->status  = OBJSTATUS_NONE;')
    800             procs_txt.append('    pNewObjNode->vkObj  = (uint64_t)(vkObj);')
    801             procs_txt.append('    %sMap[(uint64_t)vkObj] = pNewObjNode;' % (o))
    802             procs_txt.append('    uint32_t objIndex = objTypeToIndex(objType);')
    803             procs_txt.append('    numObjs[objIndex]++;')
    804             procs_txt.append('    numTotalObjs++;')
    805             procs_txt.append('}')
    806             procs_txt.append('')
    807             procs_txt.append('%s' % self.lineinfo.get())
    808             if o in vulkan.object_dispatch_list:
    809                 procs_txt.append('static void destroy_%s(%s dispatchable_object, %s object)' % (name, o, o))
    810             else:
    811                 procs_txt.append('static void destroy_%s(VkDevice dispatchable_object, %s object)' % (name, o))
    812             procs_txt.append('{')
    813             procs_txt.append('    uint64_t object_handle = (uint64_t)(object);')
    814             procs_txt.append('    auto it = %sMap.find(object_handle);' % o)
    815             procs_txt.append('    if (it != %sMap.end()) {' % o)
    816             procs_txt.append('        OBJTRACK_NODE* pNode = it->second;')
    817             procs_txt.append('        uint32_t objIndex = objTypeToIndex(pNode->objType);')
    818             procs_txt.append('        assert(numTotalObjs > 0);')
    819             procs_txt.append('        numTotalObjs--;')
    820             procs_txt.append('        assert(numObjs[objIndex] > 0);')
    821             procs_txt.append('        numObjs[objIndex]--;')
    822             procs_txt.append('        log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, pNode->objType, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",')
    823             procs_txt.append('           "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",')
    824             procs_txt.append('            string_VkDebugReportObjectTypeEXT(pNode->objType), (uint64_t)(object), numTotalObjs, numObjs[objIndex],')
    825             procs_txt.append('            string_VkDebugReportObjectTypeEXT(pNode->objType));')
    826             procs_txt.append('        delete pNode;')
    827             procs_txt.append('        %sMap.erase(it);' % (o))
    828             procs_txt.append('    } else {')
    829             procs_txt.append('        log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT ) 0, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",')
    830             procs_txt.append('            "Unable to remove obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?",')
    831             procs_txt.append('           object_handle);')
    832             procs_txt.append('    }')
    833             procs_txt.append('}')
    834             procs_txt.append('')
    835             procs_txt.append('%s' % self.lineinfo.get())
    836             if o in vulkan.object_dispatch_list:
    837                 procs_txt.append('static VkBool32 set_%s_status(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o, o))
    838             else:
    839                 procs_txt.append('static VkBool32 set_%s_status(VkDevice dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o))
    840             procs_txt.append('{')
    841             procs_txt.append('    if (object != VK_NULL_HANDLE) {')
    842             procs_txt.append('        uint64_t object_handle = (uint64_t)(object);')
    843             procs_txt.append('        auto it = %sMap.find(object_handle);' % o)
    844             procs_txt.append('        if (it != %sMap.end()) {' % o)
    845             procs_txt.append('            it->second->status |= status_flag;')
    846             procs_txt.append('        }')
    847             procs_txt.append('        else {')
    848             procs_txt.append('            // If we do not find it print an error')
    849             procs_txt.append('            return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT ) 0, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",')
    850             procs_txt.append('                "Unable to set status for non-existent object 0x%" PRIxLEAST64 " of %s type",')
    851             procs_txt.append('                object_handle, string_VkDebugReportObjectTypeEXT(objType));')
    852             procs_txt.append('        }')
    853             procs_txt.append('    }')
    854             procs_txt.append('    return VK_FALSE;')
    855             procs_txt.append('}')
    856             procs_txt.append('')
    857             procs_txt.append('%s' % self.lineinfo.get())
    858             procs_txt.append('static VkBool32 validate_%s_status(' % (name))
    859             if o in vulkan.object_dispatch_list:
    860                 procs_txt.append('%s dispatchable_object, %s object,' % (o, o))
    861             else:
    862                 procs_txt.append('VkDevice dispatchable_object, %s object,' % (o))
    863             procs_txt.append('    VkDebugReportObjectTypeEXT     objType,')
    864             procs_txt.append('    ObjectStatusFlags   status_mask,')
    865             procs_txt.append('    ObjectStatusFlags   status_flag,')
    866             procs_txt.append('    VkFlags             msg_flags,')
    867             procs_txt.append('    OBJECT_TRACK_ERROR  error_code,')
    868             procs_txt.append('    const char         *fail_msg)')
    869             procs_txt.append('{')
    870             procs_txt.append('    uint64_t object_handle = (uint64_t)(object);')
    871             procs_txt.append('    auto it = %sMap.find(object_handle);' % o)
    872             procs_txt.append('    if (it != %sMap.end()) {' % o)
    873             procs_txt.append('        OBJTRACK_NODE* pNode = it->second;')
    874             procs_txt.append('        if ((pNode->status & status_mask) != status_flag) {')
    875             procs_txt.append('            log_msg(mdd(dispatchable_object), msg_flags, pNode->objType, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",')
    876             procs_txt.append('                "OBJECT VALIDATION WARNING: %s object 0x%" PRIxLEAST64 ": %s", string_VkDebugReportObjectTypeEXT(objType),')
    877             procs_txt.append('                 object_handle, fail_msg);')
    878             procs_txt.append('            return VK_FALSE;')
    879             procs_txt.append('        }')
    880             procs_txt.append('        return VK_TRUE;')
    881             procs_txt.append('    }')
    882             procs_txt.append('    else {')
    883             procs_txt.append('        // If we do not find it print an error')
    884             procs_txt.append('        log_msg(mdd(dispatchable_object), msg_flags, (VkDebugReportObjectTypeEXT) 0, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",')
    885             procs_txt.append('            "Unable to obtain status for non-existent object 0x%" PRIxLEAST64 " of %s type",')
    886             procs_txt.append('            object_handle, string_VkDebugReportObjectTypeEXT(objType));')
    887             procs_txt.append('        return VK_FALSE;')
    888             procs_txt.append('    }')
    889             procs_txt.append('}')
    890             procs_txt.append('')
    891             procs_txt.append('%s' % self.lineinfo.get())
    892             if o in vulkan.object_dispatch_list:
    893                 procs_txt.append('static VkBool32 reset_%s_status(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o, o))
    894             else:
    895                 procs_txt.append('static VkBool32 reset_%s_status(VkDevice dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o))
    896             procs_txt.append('{')
    897             procs_txt.append('    uint64_t object_handle = (uint64_t)(object);')
    898             procs_txt.append('    auto it = %sMap.find(object_handle);' % o)
    899             procs_txt.append('    if (it != %sMap.end()) {' % o)
    900             procs_txt.append('        it->second->status &= ~status_flag;')
    901             procs_txt.append('    }')
    902             procs_txt.append('    else {')
    903             procs_txt.append('        // If we do not find it print an error')
    904             procs_txt.append('        return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",')
    905             procs_txt.append('            "Unable to reset status for non-existent object 0x%" PRIxLEAST64 " of %s type",')
    906             procs_txt.append('            object_handle, string_VkDebugReportObjectTypeEXT(objType));')
    907             procs_txt.append('    }')
    908             procs_txt.append('    return VK_FALSE;')
    909             procs_txt.append('}')
    910             procs_txt.append('')
    911         procs_txt.append('%s' % self.lineinfo.get())
    912         # Generate the permutations of validate_* functions where for each
    913         #  dispatchable object type, we have a corresponding validate_* function
    914         #  for that object and all non-dispatchable objects that are used in API
    915         #  calls with that dispatchable object.
    916         procs_txt.append('//%s' % str(obj_use_dict))
    917         for do in obj_use_dict:
    918             name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', do)
    919             name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
    920             # First create validate_* func for disp obj
    921             procs_txt.append('%s' % self.lineinfo.get())
    922             procs_txt.append('static VkBool32 validate_%s(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, bool null_allowed)' % (name, do, do))
    923             procs_txt.append('{')
    924             procs_txt.append('    if (null_allowed && (object == VK_NULL_HANDLE))')
    925             procs_txt.append('        return VK_FALSE;')
    926             procs_txt.append('    if (%sMap.find((uint64_t)object) == %sMap.end()) {' % (do, do))
    927             procs_txt.append('        return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, (uint64_t)(object), __LINE__, OBJTRACK_INVALID_OBJECT, "OBJTRACK",')
    928             procs_txt.append('            "Invalid %s Object 0x%%" PRIx64 ,(uint64_t)(object));' % do)
    929             procs_txt.append('    }')
    930             procs_txt.append('    return VK_FALSE;')
    931             procs_txt.append('}')
    932             procs_txt.append('')
    933             for o in obj_use_dict[do]:
    934                 if o == do: # We already generated this case above so skip here
    935                     continue
    936                 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', o)
    937                 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
    938                 procs_txt.append('%s' % self.lineinfo.get())
    939                 procs_txt.append('static VkBool32 validate_%s(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, bool null_allowed)' % (name, do, o))
    940                 procs_txt.append('{')
    941                 procs_txt.append('    if (null_allowed && (object == VK_NULL_HANDLE))')
    942                 procs_txt.append('        return VK_FALSE;')
    943                 if o == "VkImage":
    944                     procs_txt.append('    // We need to validate normal image objects and those from the swapchain')
    945                     procs_txt.append('    if ((%sMap.find((uint64_t)object) == %sMap.end()) &&' % (o, o))
    946                     procs_txt.append('        (swapchainImageMap.find((uint64_t)object) == swapchainImageMap.end())) {')
    947                 else:
    948                     procs_txt.append('    if (%sMap.find((uint64_t)object) == %sMap.end()) {' % (o, o))
    949                 procs_txt.append('        return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, (uint64_t)(object), __LINE__, OBJTRACK_INVALID_OBJECT, "OBJTRACK",')
    950                 procs_txt.append('            "Invalid %s Object 0x%%" PRIx64, (uint64_t)(object));' % o)
    951                 procs_txt.append('    }')
    952                 procs_txt.append('    return VK_FALSE;')
    953                 procs_txt.append('}')
    954             procs_txt.append('')
    955         procs_txt.append('')
    956         return "\n".join(procs_txt)
    957 
    958     def generate_destroy_instance(self):
    959         gedi_txt = []
    960         gedi_txt.append('%s' % self.lineinfo.get())
    961         gedi_txt.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(')
    962         gedi_txt.append('VkInstance instance,')
    963         gedi_txt.append('const VkAllocationCallbacks* pAllocator)')
    964         gedi_txt.append('{')
    965         gedi_txt.append('    loader_platform_thread_lock_mutex(&objLock);')
    966         gedi_txt.append('    validate_instance(instance, instance, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, false);')
    967         gedi_txt.append('')
    968         gedi_txt.append('    destroy_instance(instance, instance);')
    969         gedi_txt.append('    // Report any remaining objects in LL')
    970         gedi_txt.append('')
    971         gedi_txt.append('    for (auto iit = VkDeviceMap.begin(); iit != VkDeviceMap.end();) {')
    972         gedi_txt.append('        OBJTRACK_NODE* pNode = iit->second;')
    973         gedi_txt.append('        if (pNode->belongsTo == (uint64_t)instance) {')
    974         gedi_txt.append('            log_msg(mid(instance), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",')
    975         gedi_txt.append('                    "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),')
    976         gedi_txt.append('                    pNode->vkObj);')
    977         for o in vulkan.core.objects:
    978             if o in ['VkInstance', 'VkPhysicalDevice', 'VkQueue', 'VkDevice']:
    979                 continue
    980             gedi_txt.append('            for (auto idt = %sMap.begin(); idt != %sMap.end();) {' % (o, o))
    981             gedi_txt.append('                OBJTRACK_NODE* pNode = idt->second;')
    982             gedi_txt.append('                if (pNode->belongsTo == iit->first) {')
    983             gedi_txt.append('                    log_msg(mid(instance), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",')
    984             gedi_txt.append('                            "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),')
    985             gedi_txt.append('                            pNode->vkObj);')
    986             gedi_txt.append('                    %sMap.erase(idt++);' % o )
    987             gedi_txt.append('                } else {')
    988             gedi_txt.append('                    ++idt;')
    989             gedi_txt.append('                }')
    990             gedi_txt.append('            }')
    991         gedi_txt.append('            VkDeviceMap.erase(iit++);')
    992         gedi_txt.append('        } else {')
    993         gedi_txt.append('            ++iit;')
    994         gedi_txt.append('        }')
    995         gedi_txt.append('    }')
    996         gedi_txt.append('')
    997         gedi_txt.append('    dispatch_key key = get_dispatch_key(instance);')
    998         gedi_txt.append('    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(object_tracker_instance_table_map, instance);')
    999         gedi_txt.append('    pInstanceTable->DestroyInstance(instance, pAllocator);')
   1000         gedi_txt.append('')
   1001         gedi_txt.append('    layer_data *my_data = get_my_data_ptr(key, layer_data_map);')
   1002         gedi_txt.append('    // Clean up logging callback, if any')
   1003         gedi_txt.append('    while (my_data->logging_callback.size() > 0) {')
   1004         gedi_txt.append('        VkDebugReportCallbackEXT callback = my_data->logging_callback.back();')
   1005         gedi_txt.append('        layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);')
   1006         gedi_txt.append('        my_data->logging_callback.pop_back();')
   1007         gedi_txt.append('    }')
   1008         gedi_txt.append('')
   1009         gedi_txt.append('    layer_debug_report_destroy_instance(mid(instance));')
   1010         gedi_txt.append('    layer_data_map.erase(pInstanceTable);')
   1011         gedi_txt.append('')
   1012         gedi_txt.append('    instanceExtMap.erase(pInstanceTable);')
   1013         gedi_txt.append('    loader_platform_thread_unlock_mutex(&objLock);')
   1014         # The loader holds a mutex that protects this from other threads
   1015         gedi_txt.append('    object_tracker_instance_table_map.erase(key);')
   1016         gedi_txt.append('    if (object_tracker_instance_table_map.empty()) {')
   1017         gedi_txt.append('        // Release mutex when destroying last instance.')
   1018         gedi_txt.append('        loader_platform_thread_delete_mutex(&objLock);')
   1019         gedi_txt.append('        objLockInitialized = 0;')
   1020         gedi_txt.append('    }')
   1021         gedi_txt.append('}')
   1022         gedi_txt.append('')
   1023         return "\n".join(gedi_txt)
   1024 
   1025     def generate_destroy_device(self):
   1026         gedd_txt = []
   1027         gedd_txt.append('%s' % self.lineinfo.get())
   1028         gedd_txt.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(')
   1029         gedd_txt.append('VkDevice device,')
   1030         gedd_txt.append('const VkAllocationCallbacks* pAllocator)')
   1031         gedd_txt.append('{')
   1032         gedd_txt.append('    loader_platform_thread_lock_mutex(&objLock);')
   1033         gedd_txt.append('    validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);')
   1034         gedd_txt.append('')
   1035         gedd_txt.append('    destroy_device(device, device);')
   1036         gedd_txt.append('    // Report any remaining objects associated with this VkDevice object in LL')
   1037         for o in vulkan.core.objects:
   1038             # DescriptorSets and Command Buffers are destroyed through their pools, not explicitly
   1039             if o in ['VkInstance', 'VkPhysicalDevice', 'VkQueue', 'VkDevice', 'VkDescriptorSet', 'VkCommandBuffer']:
   1040                 continue
   1041             gedd_txt.append('    for (auto it = %sMap.begin(); it != %sMap.end();) {' % (o, o))
   1042             gedd_txt.append('        OBJTRACK_NODE* pNode = it->second;')
   1043             gedd_txt.append('        if (pNode->belongsTo == (uint64_t)device) {')
   1044             gedd_txt.append('            log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",')
   1045             gedd_txt.append('                    "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),')
   1046             gedd_txt.append('                    pNode->vkObj);')
   1047             gedd_txt.append('            %sMap.erase(it++);' % o )
   1048             gedd_txt.append('        } else {')
   1049             gedd_txt.append('            ++it;')
   1050             gedd_txt.append('        }')
   1051             gedd_txt.append('    }')
   1052             gedd_txt.append('')
   1053         gedd_txt.append("    // Clean up Queue's MemRef Linked Lists")
   1054         gedd_txt.append('    destroyQueueMemRefLists();')
   1055         gedd_txt.append('')
   1056         gedd_txt.append('    loader_platform_thread_unlock_mutex(&objLock);')
   1057         gedd_txt.append('')
   1058         gedd_txt.append('    dispatch_key key = get_dispatch_key(device);')
   1059         gedd_txt.append('    VkLayerDispatchTable *pDisp = get_dispatch_table(object_tracker_device_table_map, device);')
   1060         gedd_txt.append('    pDisp->DestroyDevice(device, pAllocator);')
   1061         gedd_txt.append('    object_tracker_device_table_map.erase(key);')
   1062         gedd_txt.append('')
   1063         gedd_txt.append('}')
   1064         gedd_txt.append('')
   1065         return "\n".join(gedd_txt)
   1066 
   1067     # Special-case validating some objects -- they may be non-NULL but should
   1068     # only be validated upon meeting some condition specified below.
   1069     def _dereference_conditionally(self, indent, prefix, type_name, name):
   1070         s_code = ''
   1071         if type_name == 'pBufferInfo':
   1072             s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)         ||\n'    % (indent, prefix)
   1073             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)         ||\n'    % (indent, prefix)
   1074             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||\n'    % (indent, prefix)
   1075             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)   ) {\n' % (indent, prefix)
   1076         elif type_name == 'pImageInfo':
   1077             s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)                ||\n'    % (indent, prefix)
   1078             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||\n'    % (indent, prefix)
   1079             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)       ||\n'    % (indent, prefix)
   1080             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)          ||\n'    % (indent, prefix)
   1081             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)            ) {\n' % (indent, prefix)
   1082         elif type_name == 'pTexelBufferView':
   1083             s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||\n'      % (indent, prefix)
   1084             s_code += '%s    (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)   ) {\n'   % (indent, prefix)
   1085         elif name == 'pBeginInfo->pInheritanceInfo':
   1086             s_code += '%sOBJTRACK_NODE* pNode = VkCommandBufferMap[(uint64_t)commandBuffer];\n'       % (indent)
   1087             s_code += '%sif ((%s) && (pNode->status & OBJSTATUS_COMMAND_BUFFER_SECONDARY)) {\n'       % (indent, name)
   1088         else:
   1089             s_code += '%sif (%s) {\n' % (indent, name)
   1090         return s_code
   1091 
   1092     def _gen_obj_validate_code(self, struct_uses, obj_type_mapping, func_name, valid_null_dict, param0_name, indent, prefix, array_index):
   1093         pre_code = ''
   1094         for obj in sorted(struct_uses):
   1095             name = obj
   1096             array = ''
   1097             type_name = ''
   1098             if '[' in obj:
   1099                 (name, array) = obj.split('[')
   1100                 type_name = name
   1101                 array = array.strip(']')
   1102             if isinstance(struct_uses[obj], dict):
   1103                 local_prefix = ''
   1104                 name = '%s%s' % (prefix, name)
   1105                 ptr_type = False
   1106                 if 'p' == obj[0]:
   1107                     ptr_type = True
   1108                     tmp_pre = self._dereference_conditionally(indent, prefix, type_name, name)
   1109                     pre_code += tmp_pre
   1110                     indent += '    '
   1111                 if array != '':
   1112                     idx = 'idx%s' % str(array_index)
   1113                     array_index += 1
   1114                     pre_code += '%s\n' % self.lineinfo.get()
   1115                     pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx)
   1116                     indent += '    '
   1117                     local_prefix = '%s[%s].' % (name, idx)
   1118                 elif ptr_type:
   1119                     local_prefix = '%s->' % (name)
   1120                 else:
   1121                     local_prefix = '%s.' % (name)
   1122                 tmp_pre = self._gen_obj_validate_code(struct_uses[obj], obj_type_mapping, func_name, valid_null_dict, param0_name, indent, local_prefix, array_index)
   1123                 pre_code += tmp_pre
   1124                 if array != '':
   1125                     indent = indent[4:]
   1126                     pre_code += '%s}\n' % (indent)
   1127                 if ptr_type:
   1128                     indent = indent[4:]
   1129                     pre_code += '%s}\n' % (indent)
   1130             else:
   1131                 ptype = struct_uses[obj]
   1132                 dbg_obj_type = obj_type_mapping[ptype]
   1133                 fname = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', ptype)
   1134                 fname = re.sub('([a-z0-9])([A-Z])', r'\1_\2', fname).lower()[3:]
   1135                 full_name = '%s%s' % (prefix, name)
   1136                 null_obj_ok = 'false'
   1137                 # If a valid null param is defined for this func and we have a match, allow NULL
   1138                 if func_name in valid_null_dict and True in [name in pn for pn in valid_null_dict[func_name]]:
   1139                     null_obj_ok = 'true'
   1140                 if (array_index > 0) or '' != array:
   1141                     tmp_pre = self._dereference_conditionally(indent, prefix, type_name, full_name)
   1142                     pre_code += tmp_pre
   1143                     indent += '    '
   1144                     if array != '':
   1145                         idx = 'idx%s' % str(array_index)
   1146                         array_index += 1
   1147                         pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx)
   1148                         indent += '    '
   1149                         full_name = '%s[%s]' % (full_name, idx)
   1150                     pre_code += '%s\n' % self.lineinfo.get()
   1151                     pre_code += '%sskipCall |= validate_%s(%s, %s, %s, %s);\n' %(indent, fname, param0_name, full_name, dbg_obj_type, null_obj_ok)
   1152                     if array != '':
   1153                         indent = indent[4:]
   1154                         pre_code += '%s}\n' % (indent)
   1155                     indent = indent[4:]
   1156                     pre_code += '%s}\n' % (indent)
   1157                 else:
   1158                     pre_code += '%s\n' % self.lineinfo.get()
   1159                     pre_code += '%sskipCall |= validate_%s(%s, %s, %s, %s);\n' %(indent, fname, param0_name, full_name, dbg_obj_type, null_obj_ok)
   1160         return pre_code
   1161 
   1162     def generate_intercept(self, proto, qual):
   1163         if proto.name in [ 'CreateDebugReportCallbackEXT', 'EnumerateInstanceLayerProperties', 'EnumerateInstanceExtensionProperties','EnumerateDeviceLayerProperties', 'EnumerateDeviceExtensionProperties' ]:
   1164             # use default version
   1165             return None
   1166 
   1167         # Create map of object names to object type enums of the form VkName : VkObjectTypeName
   1168         obj_type_mapping = {base_t : base_t.replace("Vk", "VkDebugReportObjectType") for base_t in vulkan.object_type_list}
   1169         # Convert object type enum names from UpperCamelCase to UPPER_CASE_WITH_UNDERSCORES
   1170         for objectName, objectTypeEnum in obj_type_mapping.items():
   1171             obj_type_mapping[objectName] = ucc_to_U_C_C(objectTypeEnum) + '_EXT';
   1172         # Command Buffer Object doesn't follow the rule.
   1173         obj_type_mapping['VkCommandBuffer'] = "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT"
   1174         obj_type_mapping['VkShaderModule'] = "VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT"
   1175 
   1176         explicit_object_tracker_functions = [
   1177             "CreateInstance",
   1178             "EnumeratePhysicalDevices",
   1179             "GetPhysicalDeviceQueueFamilyProperties",
   1180             "CreateDevice",
   1181             "GetDeviceQueue",
   1182             "QueueBindSparse",
   1183             "AllocateDescriptorSets",
   1184             "FreeDescriptorSets",
   1185             "CreateGraphicsPipelines",
   1186             "CreateComputePipelines",
   1187             "AllocateCommandBuffers",
   1188             "FreeCommandBuffers",
   1189             "DestroyDescriptorPool",
   1190             "DestroyCommandPool",
   1191             "MapMemory",
   1192             "UnmapMemory",
   1193             "FreeMemory",
   1194             "DestroySwapchainKHR",
   1195             "GetSwapchainImagesKHR"
   1196         ]
   1197         decl = proto.c_func(prefix="vk", attr="VKAPI")
   1198         param0_name = proto.params[0].name
   1199         using_line = ''
   1200         create_line = ''
   1201         destroy_line = ''
   1202         # Dict below tracks params that are vk objects. Dict is "loop count"->["params w/ that loop count"] where '0' is params that aren't in an array
   1203         # TODO : Should integrate slightly better code for this purpose from unique_objects layer
   1204         loop_params = defaultdict(list) # Dict uses loop count as key to make final code generation cleaner so params shared in single loop where needed
   1205         loop_types = defaultdict(list)
   1206         # TODO : For now skipping objs that can be NULL. Really should check these and have special case that allows them to be NULL
   1207         #  or better yet, these should be encoded into an API json definition and we generate checks from there
   1208         #  Until then, this is a dict where each func name is a list of object params that can be null (so don't need to be validated)
   1209         #   param names may be directly passed to the function, or may be a field in a struct param
   1210         valid_null_object_names = {'CreateGraphicsPipelines' : ['basePipelineHandle'],
   1211                                    'CreateComputePipelines' : ['basePipelineHandle'],
   1212                                    'BeginCommandBuffer' : ['renderPass', 'framebuffer'],
   1213                                    'QueueSubmit' : ['fence'],
   1214                                    'AcquireNextImageKHR' : ['fence', 'semaphore' ],
   1215                                    'UpdateDescriptorSets' : ['pTexelBufferView'],
   1216                                    'CreateSwapchainKHR' : ['oldSwapchain'],
   1217                                   }
   1218         param_count = 'NONE' # keep track of arrays passed directly into API functions
   1219         for p in proto.params:
   1220             base_type = p.ty.replace('const ', '').strip('*')
   1221             if 'count' in p.name.lower():
   1222                 param_count = p.name
   1223             if base_type in vulkan.core.objects:
   1224                 # This is an object to potentially check for validity. First see if it's an array
   1225                 if '*' in p.ty and 'const' in p.ty and param_count != 'NONE':
   1226                     loop_params[param_count].append(p.name)
   1227                     loop_types[param_count].append(str(p.ty[6:-1]))
   1228                 # Not an array, check for just a base Object that's not in exceptions
   1229                 elif '*' not in p.ty and (proto.name not in valid_null_object_names or p.name not in valid_null_object_names[proto.name]):
   1230                     loop_params[0].append(p.name)
   1231                     loop_types[0].append(str(p.ty))
   1232             elif vk_helper.is_type(base_type, 'struct'):
   1233                 struct_type = base_type
   1234                 if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict:
   1235                     struct_type = vk_helper.typedef_rev_dict[struct_type]
   1236                 # Parse elements of this struct param to identify objects and/or arrays of objects
   1237                 for m in sorted(vk_helper.struct_dict[struct_type]):
   1238                     if vk_helper.struct_dict[struct_type][m]['type'] in vulkan.core.objects and vk_helper.struct_dict[struct_type][m]['type'] not in ['VkPhysicalDevice', 'VkQueue', 'VkFence', 'VkImage', 'VkDeviceMemory']:
   1239                         if proto.name not in valid_null_object_names or vk_helper.struct_dict[struct_type][m]['name'] not in valid_null_object_names[proto.name]:
   1240                             # This is not great, but gets the job done for now, but If we have a count and this param is a ptr w/
   1241                             #  last letter 's' OR non-'count' string of count is in the param name, then this is a dynamically sized array param
   1242                             param_array = False
   1243                             if param_count != 'NONE':
   1244                                 if '*' in p.ty:
   1245                                     if 's' == p.name[-1] or param_count.lower().replace('count', '') in p.name.lower():
   1246                                         param_array = True
   1247                             if param_array:
   1248                                 param_name = '%s[i].%s' % (p.name, vk_helper.struct_dict[struct_type][m]['name'])
   1249                             else:
   1250                                 param_name = '%s->%s' % (p.name, vk_helper.struct_dict[struct_type][m]['name'])
   1251                             if vk_helper.struct_dict[struct_type][m]['dyn_array']:
   1252                                 if param_count != 'NONE': # this will be a double-embedded loop, use comma delineated 'count,name' for param_name
   1253                                     loop_count = '%s[i].%s' % (p.name, vk_helper.struct_dict[struct_type][m]['array_size'])
   1254                                     loop_params[param_count].append('%s,%s' % (loop_count, param_name))
   1255                                     loop_types[param_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type']))
   1256                                 else:
   1257                                     loop_count = '%s->%s' % (p.name, vk_helper.struct_dict[struct_type][m]['array_size'])
   1258                                     loop_params[loop_count].append(param_name)
   1259                                     loop_types[loop_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type']))
   1260                             else:
   1261                                 if '[' in param_name: # dynamic array param, set size
   1262                                     loop_params[param_count].append(param_name)
   1263                                     loop_types[param_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type']))
   1264                                 else:
   1265                                     loop_params[0].append(param_name)
   1266                                     loop_types[0].append('%s' % (vk_helper.struct_dict[struct_type][m]['type']))
   1267         last_param_index = None
   1268         create_func = False
   1269         if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]:
   1270             create_func = True
   1271             last_param_index = -1 # For create funcs don't validate last object
   1272         (struct_uses, local_decls) = get_object_uses(vulkan.object_type_list, proto.params[:last_param_index])
   1273         funcs = []
   1274         mutex_unlock = False
   1275         funcs.append('%s\n' % self.lineinfo.get())
   1276         if proto.name in explicit_object_tracker_functions:
   1277             funcs.append('%s%s\n'
   1278                      '{\n'
   1279                      '    return explicit_%s;\n'
   1280                      '}' % (qual, decl, proto.c_call()))
   1281             return "".join(funcs)
   1282         # Temporarily prevent  DestroySurface call from being generated until WSI layer support is fleshed out
   1283         elif 'DestroyInstance' in proto.name or 'DestroyDevice' in proto.name:
   1284             return ""
   1285         else:
   1286             if create_func:
   1287                 typ = proto.params[-1].ty.strip('*').replace('const ', '');
   1288                 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ)
   1289                 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
   1290                 create_line =  '    loader_platform_thread_lock_mutex(&objLock);\n'
   1291                 create_line += '    if (result == VK_SUCCESS) {\n'
   1292                 create_line += '        create_%s(%s, *%s, %s);\n' % (name, param0_name, proto.params[-1].name, obj_type_mapping[typ])
   1293                 create_line += '    }\n'
   1294                 create_line += '    loader_platform_thread_unlock_mutex(&objLock);\n'
   1295             if 'FreeCommandBuffers' in proto.name:
   1296                 typ = proto.params[-1].ty.strip('*').replace('const ', '');
   1297                 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ)
   1298                 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
   1299                 funcs.append('%s\n' % self.lineinfo.get())
   1300                 destroy_line =  '    loader_platform_thread_lock_mutex(&objLock);\n'
   1301                 destroy_line += '    for (uint32_t i = 0; i < commandBufferCount; i++) {\n'
   1302                 destroy_line += '        destroy_%s(%s[i], %s[i]);\n' % (name, proto.params[-1].name, proto.params[-1].name)
   1303                 destroy_line += '    }\n'
   1304                 destroy_line += '    loader_platform_thread_unlock_mutex(&objLock);\n'
   1305             if 'Destroy' in proto.name:
   1306                 typ = proto.params[-2].ty.strip('*').replace('const ', '');
   1307                 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ)
   1308                 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:]
   1309                 funcs.append('%s\n' % self.lineinfo.get())
   1310                 destroy_line =  '    loader_platform_thread_lock_mutex(&objLock);\n'
   1311                 destroy_line += '    destroy_%s(%s, %s);\n' % (name, param0_name, proto.params[-2].name)
   1312                 destroy_line += '    loader_platform_thread_unlock_mutex(&objLock);\n'
   1313             indent = '    '
   1314             if len(struct_uses) > 0:
   1315                 using_line += '%sVkBool32 skipCall = VK_FALSE;\n' % (indent)
   1316                 if not mutex_unlock:
   1317                     using_line += '%sloader_platform_thread_lock_mutex(&objLock);\n' % (indent)
   1318                     mutex_unlock = True
   1319                 using_line += '// objects to validate: %s\n' % str(struct_uses)
   1320                 using_line += self._gen_obj_validate_code(struct_uses, obj_type_mapping, proto.name, valid_null_object_names, param0_name, '    ', '', 0)
   1321             if mutex_unlock:
   1322                 using_line += '%sloader_platform_thread_unlock_mutex(&objLock);\n' % (indent)
   1323             if len(struct_uses) > 0:
   1324                 using_line += '    if (skipCall)\n'
   1325                 if proto.ret != "void":
   1326                     using_line += '        return VK_ERROR_VALIDATION_FAILED_EXT;\n'
   1327                 else:
   1328                     using_line += '        return;\n'
   1329             ret_val = ''
   1330             stmt = ''
   1331             if proto.ret != "void":
   1332                 ret_val = "%s result = " % proto.ret
   1333                 stmt = "    return result;\n"
   1334 
   1335             dispatch_param = proto.params[0].name
   1336             if 'CreateInstance' in proto.name:
   1337                dispatch_param = '*' + proto.params[1].name
   1338 
   1339             # Must use 'instance' table for these APIs, 'device' table otherwise
   1340             table_type = ""
   1341             if proto_is_global(proto):
   1342                 table_type = "instance"
   1343             else:
   1344                 table_type = "device"
   1345             if wsi_name(proto.name):
   1346                 funcs.append('%s' % wsi_ifdef(proto.name))
   1347             funcs.append('%s%s\n'
   1348                      '{\n'
   1349                      '%s'
   1350                      '%s'
   1351                      '    %sget_dispatch_table(object_tracker_%s_table_map, %s)->%s;\n'
   1352                      '%s'
   1353                      '%s'
   1354                      '}' % (qual, decl, using_line, destroy_line, ret_val, table_type, dispatch_param, proto.c_call(), create_line, stmt))
   1355             if wsi_name(proto.name):
   1356                 funcs.append('%s' % wsi_endif(proto.name))
   1357         return "\n\n".join(funcs)
   1358 
   1359     def generate_body(self):
   1360         self.layer_name = "object_tracker"
   1361         extensions=[('wsi_enabled',
   1362                      ['vkCreateSwapchainKHR',
   1363                       'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR',
   1364                       'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])]
   1365         if self.wsi == 'Win32':
   1366             instance_extensions=[('msg_callback_get_proc_addr', []),
   1367                                   ('wsi_enabled',
   1368                                   ['vkDestroySurfaceKHR',
   1369                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1370                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1371                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1372                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1373                                    'vkCreateWin32SurfaceKHR',
   1374                                    'vkGetPhysicalDeviceWin32PresentationSupportKHR'])]
   1375         elif self.wsi == 'Android':
   1376             instance_extensions=[('msg_callback_get_proc_addr', []),
   1377                                   ('wsi_enabled',
   1378                                   ['vkDestroySurfaceKHR',
   1379                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1380                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1381                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1382                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1383                                    'vkCreateAndroidSurfaceKHR'])]
   1384         elif self.wsi == 'Xcb' or self.wsi == 'Xlib' or self.wsi == 'Wayland' or self.wsi == 'Mir':
   1385             instance_extensions=[('msg_callback_get_proc_addr', []),
   1386                                   ('wsi_enabled',
   1387                                   ['vkDestroySurfaceKHR',
   1388                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1389                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1390                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1391                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1392                                    'vkCreateXcbSurfaceKHR',
   1393                                    'vkGetPhysicalDeviceXcbPresentationSupportKHR',
   1394                                    'vkCreateXlibSurfaceKHR',
   1395                                    'vkGetPhysicalDeviceXlibPresentationSupportKHR',
   1396                                    'vkCreateWaylandSurfaceKHR',
   1397                                    'vkGetPhysicalDeviceWaylandPresentationSupportKHR',
   1398                                    'vkCreateMirSurfaceKHR',
   1399                                    'vkGetPhysicalDeviceMirPresentationSupportKHR'])]
   1400         else:
   1401             print('Error: Undefined DisplayServer')
   1402             instance_extensions=[]
   1403 
   1404         body = [self.generate_maps(),
   1405                 self.generate_procs(),
   1406                 self.generate_destroy_instance(),
   1407                 self.generate_destroy_device(),
   1408                 self._generate_dispatch_entrypoints("VK_LAYER_EXPORT"),
   1409                 self._generate_extensions(),
   1410                 self._generate_layer_gpa_function(extensions,
   1411                                                   instance_extensions)]
   1412         return "\n\n".join(body)
   1413 
   1414 class UniqueObjectsSubcommand(Subcommand):
   1415     def generate_header(self):
   1416         header_txt = []
   1417         header_txt.append('%s' % self.lineinfo.get())
   1418         header_txt.append('#include "unique_objects.h"')
   1419         return "\n".join(header_txt)
   1420 
   1421     # Generate UniqueObjects code for given struct_uses dict of objects that need to be unwrapped
   1422     # vector_name_set is used to make sure we don't replicate vector names
   1423     # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct
   1424     # TODO : Comment this code
   1425     def _gen_obj_code(self, struct_uses, param_type, indent, prefix, array_index, vector_name_set, first_level_param):
   1426         decls = ''
   1427         pre_code = ''
   1428         post_code = ''
   1429         for obj in sorted(struct_uses):
   1430             name = obj
   1431             array = ''
   1432             if '[' in obj:
   1433                 (name, array) = obj.split('[')
   1434                 array = array.strip(']')
   1435             ptr_type = False
   1436             if 'p' == obj[0] and obj[1] != obj[1].lower(): # TODO : Not idea way to determine ptr
   1437                 ptr_type = True
   1438             if isinstance(struct_uses[obj], dict):
   1439                 local_prefix = ''
   1440                 name = '%s%s' % (prefix, name)
   1441                 if ptr_type:
   1442                     if first_level_param and name in param_type:
   1443                         pre_code += '%sif (%s) {\n' % (indent, name)
   1444                     else: # shadow ptr will have been initialized at this point so check it vs. source ptr
   1445                         pre_code += '%sif (local_%s) {\n' % (indent, name)
   1446                     indent += '    '
   1447                 if array != '':
   1448                     idx = 'idx%s' % str(array_index)
   1449                     array_index += 1
   1450                     if first_level_param and name in param_type:
   1451                         pre_code += '%slocal_%s = new safe_%s[%s];\n' % (indent, name, param_type[name].strip('*'), array)
   1452                         post_code += '    if (local_%s)\n' % (name)
   1453                         post_code += '        delete[] local_%s;\n' % (name)
   1454                     pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx)
   1455                     indent += '    '
   1456                     if first_level_param:
   1457                         pre_code += '%slocal_%s[%s].initialize(&%s[%s]);\n' % (indent, name, idx, name, idx)
   1458                     local_prefix = '%s[%s].' % (name, idx)
   1459                 elif ptr_type:
   1460                     if first_level_param and name in param_type:
   1461                         pre_code += '%slocal_%s = new safe_%s(%s);\n' % (indent, name, param_type[name].strip('*'), name)
   1462                         post_code += '    if (local_%s)\n' % (name)
   1463                         post_code += '        delete local_%s;\n' % (name)
   1464                     local_prefix = '%s->' % (name)
   1465                 else:
   1466                     local_prefix = '%s.' % (name)
   1467                 assert isinstance(decls, object)
   1468                 (tmp_decl, tmp_pre, tmp_post) = self._gen_obj_code(struct_uses[obj], param_type, indent, local_prefix, array_index, vector_name_set, False)
   1469                 decls += tmp_decl
   1470                 pre_code += tmp_pre
   1471                 post_code += tmp_post
   1472                 if array != '':
   1473                     indent = indent[4:]
   1474                     pre_code += '%s}\n' % (indent)
   1475                 if ptr_type:
   1476                     indent = indent[4:]
   1477                     pre_code += '%s}\n' % (indent)
   1478             else:
   1479                 if (array_index > 0) or array != '': # TODO : This is not ideal, really want to know if we're anywhere under an array
   1480                     if first_level_param:
   1481                         pre_code += '%s%s* local_%s = NULL;\n' % (indent, struct_uses[obj], name)
   1482                     if array != '' and not first_level_param: # ptrs under structs will have been initialized so use local_*
   1483                         pre_code += '%sif (local_%s%s) {\n' %(indent, prefix, name)
   1484                     else:
   1485                         pre_code += '%sif (%s%s) {\n' %(indent, prefix, name)
   1486                     indent += '    '
   1487                     if array != '':
   1488                         idx = 'idx%s' % str(array_index)
   1489                         array_index += 1
   1490                         if first_level_param:
   1491                             pre_code += '%slocal_%s = new %s[%s];\n' % (indent, name, struct_uses[obj], array)
   1492                             post_code += '    if (local_%s)\n' % (name)
   1493                             post_code += '        delete[] local_%s;\n' % (name)
   1494                         pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx)
   1495                         indent += '    '
   1496                         name = '%s[%s]' % (name, idx)
   1497                     pName = 'p%s' % (struct_uses[obj][2:])
   1498                     if name not in vector_name_set:
   1499                         vector_name_set.add(name)
   1500                     pre_code += '%slocal_%s%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, prefix, name, struct_uses[obj], prefix, name)
   1501                     if array != '':
   1502                         indent = indent[4:]
   1503                         pre_code += '%s}\n' % (indent)
   1504                     indent = indent[4:]
   1505                     pre_code += '%s}\n' % (indent)
   1506                 else:
   1507                     pre_code += '%s\n' % (self.lineinfo.get())
   1508                     pre_code += '%sif (%s%s) {\n' %(indent, prefix, name)
   1509                     indent += '    '
   1510                     deref_txt = '&'
   1511                     if ptr_type:
   1512                         deref_txt = ''
   1513                     if '->' in prefix: # need to update local struct
   1514                         pre_code += '%slocal_%s%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, prefix, name, struct_uses[obj], prefix, name)
   1515                     else:
   1516                         pre_code += '%s%s* p%s = (%s*)%s%s%s;\n' % (indent, struct_uses[obj], name, struct_uses[obj], deref_txt, prefix, name)
   1517                         pre_code += '%s*p%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, name, struct_uses[obj], prefix, name)
   1518                     indent = indent[4:]
   1519                     pre_code += '%s}\n' % (indent)
   1520         return decls, pre_code, post_code
   1521 
   1522     def generate_intercept(self, proto, qual):
   1523         create_func = False
   1524         destroy_func = False
   1525         last_param_index = None #typcially we look at all params for ndos
   1526         pre_call_txt = '' # code prior to calling down chain such as unwrap uses of ndos
   1527         post_call_txt = '' # code following call down chain such to wrap newly created ndos, or destroy local wrap struct
   1528         funcs = []
   1529         indent = '    ' # indent level for generated code
   1530         decl = proto.c_func(prefix="vk", attr="VKAPI")
   1531         # A few API cases that are manual code
   1532         # TODO : Special case Create*Pipelines funcs to handle creating multiple unique objects
   1533         explicit_object_tracker_functions = ['GetSwapchainImagesKHR',
   1534                                              'CreateInstance',
   1535                                              'CreateDevice',
   1536                                              'CreateComputePipelines',
   1537                                              'CreateGraphicsPipelines'
   1538                                              ]
   1539         # TODO : This is hacky, need to make this a more general-purpose solution for all layers
   1540         ifdef_dict = {'CreateXcbSurfaceKHR': 'VK_USE_PLATFORM_XCB_KHR',
   1541                       'CreateAndroidSurfaceKHR': 'VK_USE_PLATFORM_ANDROID_KHR',
   1542                       'CreateWin32SurfaceKHR': 'VK_USE_PLATFORM_WIN32_KHR'}
   1543         # Give special treatment to create functions that return multiple new objects
   1544         # This dict stores array name and size of array
   1545         custom_create_dict = {'pDescriptorSets' : 'pAllocateInfo->descriptorSetCount'}
   1546         pre_call_txt += '%s\n' % (self.lineinfo.get())
   1547         if proto.name in explicit_object_tracker_functions:
   1548             funcs.append('%s%s\n'
   1549                      '{\n'
   1550                      '    return explicit_%s;\n'
   1551                      '}' % (qual, decl, proto.c_call()))
   1552             return "".join(funcs)
   1553         if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]:
   1554             create_func = True
   1555             last_param_index = -1 # For create funcs don't care if last param is ndo
   1556         if True in [destroy_txt in proto.name for destroy_txt in ['Destroy', 'Free']]:
   1557             destroy_obj_type = proto.params[-2].ty
   1558             if destroy_obj_type in vulkan.object_non_dispatch_list:
   1559                 destroy_func = True
   1560 
   1561         # First thing we need to do is gather uses of non-dispatchable-objects (ndos)
   1562         (struct_uses, local_decls) = get_object_uses(vulkan.object_non_dispatch_list, proto.params[1:last_param_index])
   1563 
   1564         if len(struct_uses) > 0:
   1565             pre_call_txt += '// STRUCT USES:%s\n' % struct_uses
   1566             if len(local_decls) > 0:
   1567                 pre_call_txt += '//LOCAL DECLS:%s\n' % local_decls
   1568             if destroy_func: # only one object
   1569                 for del_obj in struct_uses:
   1570                     pre_call_txt += '%s%s local_%s = %s;\n' % (indent, struct_uses[del_obj], del_obj, del_obj)
   1571             (pre_decl, pre_code, post_code) = self._gen_obj_code(struct_uses, local_decls, '    ', '', 0, set(), True)
   1572             # This is a bit hacky but works for now. Need to decl local versions of top-level structs
   1573             for ld in local_decls:
   1574                 init_null_txt = 'NULL';
   1575                 if '*' not in local_decls[ld]:
   1576                     init_null_txt = '{}';
   1577                 if local_decls[ld].strip('*') not in vulkan.object_non_dispatch_list:
   1578                     pre_decl += '    safe_%s local_%s = %s;\n' % (local_decls[ld], ld, init_null_txt)
   1579             pre_call_txt += '%s%s' % (pre_decl, pre_code)
   1580             post_call_txt += '%s' % (post_code)
   1581         elif create_func:
   1582             base_type = proto.params[-1].ty.replace('const ', '').strip('*')
   1583             if base_type not in vulkan.object_non_dispatch_list:
   1584                 return None
   1585         else:
   1586             return None
   1587 
   1588         ret_val = ''
   1589         ret_stmt = ''
   1590         if proto.ret != "void":
   1591             ret_val = "%s result = " % proto.ret
   1592             ret_stmt = "    return result;\n"
   1593         dispatch_param = proto.params[0].name
   1594         if 'CreateInstance' in proto.name:
   1595            dispatch_param = '*' + proto.params[1].name
   1596         if create_func:
   1597             obj_type = proto.params[-1].ty.strip('*')
   1598             obj_name = proto.params[-1].name
   1599             if obj_type in vulkan.object_non_dispatch_list:
   1600                 local_name = "unique%s" % obj_type[2:]
   1601                 post_call_txt += '%sif (VK_SUCCESS == result) {\n' % (indent)
   1602                 indent += '    '
   1603                 if obj_name in custom_create_dict:
   1604                     post_call_txt += '%s\n' % (self.lineinfo.get())
   1605                     local_name = '%ss' % (local_name) # add 's' to end for vector of many
   1606                     post_call_txt += '%sstd::vector<VkUniqueObject*> %s = {};\n' % (indent, local_name)
   1607                     post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, custom_create_dict[obj_name])
   1608                     indent += '    '
   1609                     post_call_txt += '%s%s.push_back(new VkUniqueObject());\n' % (indent, local_name)
   1610                     post_call_txt += '%s%s[i]->actualObject = (uint64_t)%s[i];\n' % (indent, local_name, obj_name)
   1611                     post_call_txt += '%s%s[i] = (%s)%s[i];\n' % (indent, obj_name, obj_type, local_name)
   1612                     indent = indent[4:]
   1613                     post_call_txt += '%s}\n' % (indent)
   1614                 else:
   1615                     post_call_txt += '%s\n' % (self.lineinfo.get())
   1616                     post_call_txt += '%sVkUniqueObject* %s = new VkUniqueObject();\n' % (indent, local_name)
   1617                     post_call_txt += '%s%s->actualObject = (uint64_t)*%s;\n' % (indent, local_name, obj_name)
   1618                     post_call_txt += '%s*%s = (%s)%s;\n' % (indent, obj_name, obj_type, local_name)
   1619                 indent = indent[4:]
   1620                 post_call_txt += '%s}\n' % (indent)
   1621         elif destroy_func:
   1622             del_obj = proto.params[-2].name
   1623             if 'count' in del_obj.lower():
   1624                 post_call_txt += '%s\n' % (self.lineinfo.get())
   1625                 post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, del_obj)
   1626                 del_obj = proto.params[-1].name
   1627                 indent += '    '
   1628                 post_call_txt += '%sdelete (VkUniqueObject*)%s[i];\n' % (indent, del_obj)
   1629                 indent = indent[4:]
   1630                 post_call_txt += '%s}\n' % (indent)
   1631             else:
   1632                 post_call_txt += '%s\n' % (self.lineinfo.get())
   1633                 post_call_txt = '%sdelete (VkUniqueObject*)local_%s;\n' % (indent, proto.params[-2].name)
   1634 
   1635         call_sig = proto.c_call()
   1636         # Replace default params with any custom local params
   1637         for ld in local_decls:
   1638             call_sig = call_sig.replace(ld, '(const %s)local_%s' % (local_decls[ld], ld))
   1639         if proto_is_global(proto):
   1640             table_type = "instance"
   1641         else:
   1642             table_type = "device"
   1643         pre_call_txt += '%s\n' % (self.lineinfo.get())
   1644         open_ifdef = ''
   1645         close_ifdef = ''
   1646         if proto.name in ifdef_dict:
   1647             open_ifdef = '#ifdef %s\n' % (ifdef_dict[proto.name])
   1648             close_ifdef = '#endif\n'
   1649         funcs.append('%s'
   1650                      '%s%s\n'
   1651                      '{\n'
   1652                      '%s'
   1653                      '    %sget_dispatch_table(unique_objects_%s_table_map, %s)->%s;\n'
   1654                      '%s'
   1655                      '%s'
   1656                      '}\n'
   1657                      '%s' % (open_ifdef, qual, decl, pre_call_txt, ret_val, table_type, dispatch_param, call_sig, post_call_txt, ret_stmt, close_ifdef))
   1658         return "\n\n".join(funcs)
   1659 
   1660     def generate_body(self):
   1661         self.layer_name = "unique_objects"
   1662         extensions=[('wsi_enabled',
   1663                      ['vkCreateSwapchainKHR',
   1664                       'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR',
   1665                       'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])]
   1666         if self.wsi == 'Win32':
   1667             instance_extensions=[('wsi_enabled',
   1668                                   ['vkDestroySurfaceKHR',
   1669                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1670                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1671                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1672                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1673                                    'vkCreateWin32SurfaceKHR'
   1674                                    ])]
   1675         elif self.wsi == 'Android':
   1676             instance_extensions=[('wsi_enabled',
   1677                                   ['vkDestroySurfaceKHR',
   1678                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1679                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1680                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1681                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1682                                    'vkCreateAndroidSurfaceKHR'])]
   1683         elif self.wsi == 'Xcb' or self.wsi == 'Xlib' or self.wsi == 'Wayland' or self.wsi == 'Mir':
   1684             instance_extensions=[('wsi_enabled',
   1685                                   ['vkDestroySurfaceKHR',
   1686                                    'vkGetPhysicalDeviceSurfaceSupportKHR',
   1687                                    'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
   1688                                    'vkGetPhysicalDeviceSurfaceFormatsKHR',
   1689                                    'vkGetPhysicalDeviceSurfacePresentModesKHR',
   1690                                    'vkCreateXcbSurfaceKHR',
   1691                                    'vkCreateXlibSurfaceKHR',
   1692                                    'vkCreateWaylandSurfaceKHR',
   1693                                    'vkCreateMirSurfaceKHR'
   1694                                    ])]
   1695         else:
   1696             print('Error: Undefined DisplayServer')
   1697             instance_extensions=[]
   1698 
   1699         body = [self._generate_dispatch_entrypoints("VK_LAYER_EXPORT"),
   1700                 self._generate_layer_gpa_function(extensions,
   1701                                                   instance_extensions)]
   1702         return "\n\n".join(body)
   1703 
   1704 def main():
   1705     wsi = {
   1706             "Win32",
   1707             "Android",
   1708             "Xcb",
   1709             "Xlib",
   1710             "Wayland",
   1711             "Mir",
   1712     }
   1713 
   1714     subcommands = {
   1715             "object_tracker" : ObjectTrackerSubcommand,
   1716             "unique_objects" : UniqueObjectsSubcommand,
   1717     }
   1718 
   1719     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]):
   1720         print("Usage: %s <wsi> <subcommand> <input_header> [options]" % sys.argv[0])
   1721         print
   1722         print("Available subcommands are: %s" % " ".join(subcommands))
   1723         exit(1)
   1724 
   1725     hfp = vk_helper.HeaderFileParser(sys.argv[3])
   1726     hfp.parse()
   1727     vk_helper.enum_val_dict = hfp.get_enum_val_dict()
   1728     vk_helper.enum_type_dict = hfp.get_enum_type_dict()
   1729     vk_helper.struct_dict = hfp.get_struct_dict()
   1730     vk_helper.typedef_fwd_dict = hfp.get_typedef_fwd_dict()
   1731     vk_helper.typedef_rev_dict = hfp.get_typedef_rev_dict()
   1732     vk_helper.types_dict = hfp.get_types_dict()
   1733 
   1734     subcmd = subcommands[sys.argv[2]](sys.argv[3:])
   1735     subcmd.run()
   1736 
   1737 if __name__ == "__main__":
   1738     main()
   1739