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