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