1#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2022 The Khronos Group Inc.
4# Copyright (c) 2015-2022 Valve Corporation
5# Copyright (c) 2015-2022 LunarG, Inc.
6# Copyright (c) 2015-2017 Google Inc.
7# Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
8# Copyright (c) 2023-2023 RasterGrid Kft.
9#
10# Licensed under the Apache License, Version 2.0 (the "License");
11# you may not use this file except in compliance with the License.
12# You may obtain a copy of the License at
13#
14#     http://www.apache.org/licenses/LICENSE-2.0
15#
16# Unless required by applicable law or agreed to in writing, software
17# distributed under the License is distributed on an "AS IS" BASIS,
18# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19# See the License for the specific language governing permissions and
20# limitations under the License.
21#
22# Author: Mark Young <marky@lunarg.com>
23# Author: Mark Lobodzinski <mark@lunarg.com>
24
25import os,re,sys
26import xml.etree.ElementTree as etree
27from generator import *
28from collections import namedtuple
29from common_codegen import *
30
31
32WSI_EXT_NAMES = ['VK_KHR_surface',
33                 'VK_KHR_display',
34                 'VK_KHR_xlib_surface',
35                 'VK_KHR_xcb_surface',
36                 'VK_KHR_wayland_surface',
37                 'VK_EXT_directfb_surface',
38                 'VK_KHR_win32_surface',
39                 'VK_KHR_android_surface',
40                 'VK_GGP_stream_descriptor_surface',
41                 'VK_MVK_macos_surface',
42                 'VK_MVK_ios_surface',
43                 'VK_EXT_headless_surface',
44                 'VK_EXT_metal_surface',
45                 'VK_FUCHSIA_imagepipe_surface',
46                 'VK_KHR_swapchain',
47                 'VK_KHR_display_swapchain',
48                 'VK_KHR_get_display_properties2',
49                 'VK_KHR_get_surface_capabilities2',
50                 'VK_QNX_screen_surface',
51                 'VK_NN_vi_surface',
52                 'VK_OHOS_surface']
53
54ADD_INST_CMDS = ['vkCreateInstance',
55                 'vkEnumerateInstanceExtensionProperties',
56                 'vkEnumerateInstanceLayerProperties',
57                 'vkEnumerateInstanceVersion']
58
59AVOID_EXT_NAMES = ['VK_EXT_debug_report']
60
61NULL_CHECK_EXT_NAMES= ['VK_EXT_debug_utils']
62
63AVOID_CMD_NAMES = ['vkCreateDebugUtilsMessengerEXT',
64                   'vkDestroyDebugUtilsMessengerEXT',
65                   'vkSubmitDebugUtilsMessageEXT']
66
67DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr',
68                         'vkCreateSwapchainKHR',
69                         'vkCreateSharedSwapchainsKHR',
70                         'vkGetDeviceGroupSurfacePresentModesKHR',
71                         'vkDebugMarkerSetObjectTagEXT',
72                         'vkDebugMarkerSetObjectNameEXT',
73                         'vkSetDebugUtilsObjectNameEXT',
74                         'vkSetDebugUtilsObjectTagEXT',
75                         'vkQueueBeginDebugUtilsLabelEXT',
76                         'vkQueueEndDebugUtilsLabelEXT',
77                         'vkQueueInsertDebugUtilsLabelEXT',
78                         'vkCmdBeginDebugUtilsLabelEXT',
79                         'vkCmdEndDebugUtilsLabelEXT',
80                         'vkCmdInsertDebugUtilsLabelEXT',
81                         'vkGetDeviceGroupSurfacePresentModes2EXT']
82
83DEVICE_CMDS_MUST_USE_TRAMP = ['vkSetDebugUtilsObjectNameEXT',
84                              'vkSetDebugUtilsObjectTagEXT',
85                              'vkDebugMarkerSetObjectNameEXT',
86                              'vkDebugMarkerSetObjectTagEXT']
87
88# These are the aliased functions that use the same terminator for both extension and core versions
89# Generally, this is only applies to physical device level functions in instance extensions
90SHARED_ALIASES = {
91    # 1.1 aliases
92    'vkEnumeratePhysicalDeviceGroupsKHR':                   'vkEnumeratePhysicalDeviceGroups',
93    'vkGetPhysicalDeviceFeatures2KHR':                      'vkGetPhysicalDeviceFeatures2',
94    'vkGetPhysicalDeviceProperties2KHR':                    'vkGetPhysicalDeviceProperties2',
95    'vkGetPhysicalDeviceFormatProperties2KHR':              'vkGetPhysicalDeviceFormatProperties2',
96    'vkGetPhysicalDeviceImageFormatProperties2KHR':         'vkGetPhysicalDeviceImageFormatProperties2',
97    'vkGetPhysicalDeviceQueueFamilyProperties2KHR':         'vkGetPhysicalDeviceQueueFamilyProperties2',
98    'vkGetPhysicalDeviceMemoryProperties2KHR':              'vkGetPhysicalDeviceMemoryProperties2',
99    'vkGetPhysicalDeviceSparseImageFormatProperties2KHR':   'vkGetPhysicalDeviceSparseImageFormatProperties2',
100    'vkGetPhysicalDeviceExternalBufferPropertiesKHR':       'vkGetPhysicalDeviceExternalBufferProperties',
101    'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR':    'vkGetPhysicalDeviceExternalSemaphoreProperties',
102    'vkGetPhysicalDeviceExternalFencePropertiesKHR':        'vkGetPhysicalDeviceExternalFenceProperties',
103}
104
105PRE_INSTANCE_FUNCTIONS = ['vkEnumerateInstanceExtensionProperties',
106                          'vkEnumerateInstanceLayerProperties',
107                          'vkEnumerateInstanceVersion']
108
109#
110# API Version
111class APIVersion:
112    def __init__(self, token, apiname = 'Vulkan', supported = True):
113        self.token = token
114        self.constant = token.replace('_VERSION_', '_API_VERSION_')
115        self.number = token[token.find('_VERSION_') + len('_VERSION_'):].replace('_', '.')
116        self.name = f'{apiname} {self.number}'
117        self.supported = supported
118
119#
120# LoaderExtensionGeneratorOptions - subclass of GeneratorOptions.
121class LoaderExtensionGeneratorOptions(GeneratorOptions):
122    def __init__(self,
123                 conventions = None,
124                 filename = None,
125                 directory = '.',
126                 genpath = None,
127                 apiname = None,
128                 profile = None,
129                 versions = '.*',
130                 emitversions = '.*',
131                 defaultExtensions = None,
132                 addExtensions = None,
133                 removeExtensions = None,
134                 emitExtensions = None,
135                 sortProcedure = regSortFeatures,
136                 prefixText = "",
137                 genFuncPointers = True,
138                 protectFile = True,
139                 protectFeature = True,
140                 apicall = '',
141                 apientry = '',
142                 apientryp = '',
143                 indentFuncProto = True,
144                 indentFuncPointer = False,
145                 alignFuncParam = 0,
146                 expandEnumerants = True):
147        GeneratorOptions.__init__(self,
148                conventions = conventions,
149                filename = filename,
150                directory = directory,
151                genpath = genpath,
152                apiname = apiname,
153                profile = profile,
154                versions = versions,
155                emitversions = emitversions,
156                defaultExtensions = defaultExtensions,
157                addExtensions = addExtensions,
158                removeExtensions = removeExtensions,
159                emitExtensions = emitExtensions,
160                sortProcedure = sortProcedure)
161        self.prefixText      = prefixText
162        self.prefixText      = None
163        self.apicall         = apicall
164        self.apientry        = apientry
165        self.apientryp       = apientryp
166        self.alignFuncParam  = alignFuncParam
167        self.expandEnumerants = expandEnumerants
168
169#
170# LoaderExtensionOutputGenerator - subclass of OutputGenerator.
171# Generates dispatch table helper header files for LVL
172class LoaderExtensionOutputGenerator(OutputGenerator):
173    """Generate dispatch table helper header based on XML element attributes"""
174    def __init__(self,
175                 errFile = sys.stderr,
176                 warnFile = sys.stderr,
177                 diagFile = sys.stdout):
178        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
179
180        # Internal state - accumulators for different inner block text
181        self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
182        self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
183        self.core_commands = []               # List of CommandData records for core Vulkan commands
184        self.ext_commands = []                # List of CommandData records for extension Vulkan commands
185        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
186        self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'require', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
187        self.instanceExtensions = []
188        self.ExtensionData = namedtuple('ExtensionData', ['name', 'type', 'protect', 'define', 'num_commands'])
189
190    #
191    # Called once at the beginning of each run
192    def beginFile(self, genOpts):
193        OutputGenerator.beginFile(self, genOpts)
194
195        # User-supplied prefix text, if any (list of strings)
196        if (genOpts.prefixText):
197            for s in genOpts.prefixText:
198                write(s, file=self.outFile)
199
200        # File Comment
201        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
202        file_comment += '// See loader_extension_generator.py for modifications\n'
203        write(file_comment, file=self.outFile)
204
205        # Copyright Notice
206        copyright =  '/*\n'
207        copyright += ' * Copyright (c) 2015-2022 The Khronos Group Inc.\n'
208        copyright += ' * Copyright (c) 2015-2022 Valve Corporation\n'
209        copyright += ' * Copyright (c) 2015-2022 LunarG, Inc.\n'
210        copyright += ' * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n'
211        copyright += ' * Copyright (c) 2023-2023 RasterGrid Kft.\n'
212        copyright += ' *\n'
213        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
214        copyright += ' * you may not use this file except in compliance with the License.\n'
215        copyright += ' * You may obtain a copy of the License at\n'
216        copyright += ' *\n'
217        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
218        copyright += ' *\n'
219        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
220        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
221        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
222        copyright += ' * See the License for the specific language governing permissions and\n'
223        copyright += ' * limitations under the License.\n'
224        copyright += ' *\n'
225        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
226        copyright += ' * Author: Mark Young <marky@lunarg.com>\n'
227        copyright += ' */\n'
228
229        preamble = ''
230
231        preamble += '// clang-format off\n'
232
233        if self.genOpts.filename == 'vk_loader_extensions.h':
234            preamble += '#pragma once\n'
235
236        elif self.genOpts.filename == 'vk_loader_extensions.c':
237            preamble += '#include <stdio.h>\n'
238            preamble += '#include <stdlib.h>\n'
239            preamble += '#include <string.h>\n'
240            preamble += '#include "vk_loader_platform.h"\n'
241            preamble += '#include "loader.h"\n'
242            preamble += '#include "vk_loader_extensions.h"\n'
243            preamble += '#include <vulkan/vk_icd.h>\n'
244            preamble += '#include "wsi.h"\n'
245            preamble += '#include "debug_utils.h"\n'
246            preamble += '#include "extension_manual.h"\n'
247
248        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
249            preamble += '#pragma once\n'
250            preamble += '\n'
251            preamble += '#if !defined(PFN_GetPhysicalDeviceProcAddr)\n'
252            preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
253            preamble += '#endif\n'
254
255        write(copyright, file=self.outFile)
256        write(preamble, file=self.outFile)
257
258    #
259    # Write generate and write dispatch tables to output file
260    def endFile(self):
261        file_data = ''
262
263        if self.genOpts.filename == 'vk_loader_extensions.h':
264            file_data += self.OutputPrototypesInHeader()
265            file_data += self.OutputLoaderTerminators()
266            file_data += self.OutputIcdDispatchTable()
267            file_data += self.OutputIcdExtensionEnableUnion()
268            file_data += self.OutputDeviceFunctionTerminatorDispatchTable()
269
270        elif self.genOpts.filename == 'vk_loader_extensions.c':
271            file_data += self.OutputUtilitiesInSource()
272            file_data += self.OutputIcdDispatchTableInit()
273            file_data += self.OutputLoaderDispatchTables()
274            file_data += self.InitDeviceFunctionTerminatorDispatchTable()
275            file_data += self.OutputDeviceFunctionTrampolinePrototypes()
276            file_data += self.OutputLoaderLookupFunc()
277            file_data += self.CreateTrampTermFuncs()
278            file_data += self.InstExtensionGPA()
279            file_data += self.InstantExtensionCreate()
280            file_data += self.DeviceExtensionGetTerminator()
281            file_data += self.InitInstLoaderExtensionDispatchTable()
282            file_data += self.OutputInstantExtensionWhitelistArray()
283
284        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
285            file_data += self.OutputLayerInstanceDispatchTable()
286            file_data += self.OutputLayerDeviceDispatchTable()
287
288        file_data += '// clang-format on'
289
290        write(file_data, file=self.outFile);
291
292        # Finish processing in superclass
293        OutputGenerator.endFile(self)
294
295    def beginFeature(self, interface, emit):
296        # Start processing in superclass
297        OutputGenerator.beginFeature(self, interface, emit)
298        self.featureExtraProtect = GetFeatureProtect(interface)
299
300        enums = interface[0].findall('enum')
301        self.currentExtension = ''
302        self.name_definition = ''
303
304        for item in enums:
305            name_definition = item.get('name')
306            if 'EXTENSION_NAME' in name_definition:
307                self.name_definition = name_definition
308
309        self.type = interface.get('type')
310        self.num_commands = 0
311        name = interface.get('name')
312        self.currentExtension = name
313
314    #
315    # Process commands, adding to appropriate dispatch tables
316    def genCmd(self, cmdinfo, name, alias):
317        OutputGenerator.genCmd(self, cmdinfo, name, alias)
318
319        # Get first param type
320        params = cmdinfo.elem.findall('param')
321        info = self.getTypeNameTuple(params[0])
322
323        self.num_commands += 1
324
325        if 'android' not in name:
326            self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
327
328    def endFeature(self):
329
330        if 'android' not in self.currentExtension:
331            self.instanceExtensions.append(self.ExtensionData(name=self.currentExtension,
332                                                              type=self.type,
333                                                              protect=self.featureExtraProtect,
334                                                              define=self.name_definition,
335                                                              num_commands=self.num_commands))
336
337        # Finish processing in superclass
338        OutputGenerator.endFeature(self)
339
340    #
341    # Retrieve the value of the len tag
342    def getLen(self, param):
343        result = None
344        len = param.attrib.get('len')
345        if len and len != 'null-terminated':
346            # For string arrays, 'len' can look like 'count,null-terminated',
347            # indicating that we have a null terminated array of strings.  We
348            # strip the null-terminated from the 'len' field and only return
349            # the parameter specifying the string count
350            if 'null-terminated' in len:
351                result = len.split(',')[0]
352            else:
353                result = len
354            result = str(result).replace('::', '->')
355        return result
356
357    #
358    # Returns an APIVersion object corresponding to the specified version token or None
359    def getAPIVersion(self, token):
360        if self.genOpts.apiname == 'vulkansc':
361            if token in ['VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2']:
362                # Vulkan 1.0-1.2 is included in Vulkan SC 1.0
363                token = 'VKSC_VERSION_1_0'
364
365            if token.startswith('VKSC_VERSION_'):
366                return APIVersion(token, 'Vulkan SC', True)
367            elif token.startswith('VK_VERSION_'):
368                # Unsupported Vulkan version
369                return APIVersion(token, 'Vulkan', False)
370            else:
371                return None
372
373        if token.startswith('VK_VERSION_'):
374            return APIVersion(token)
375        return None
376
377    #
378    # Determine if this API should be ignored or added to the instance or device dispatch table
379    def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
380        handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
381
382        return_type =  cmdinfo.elem.find('proto/type')
383        if (return_type is not None and return_type.text == 'void'):
384           return_type = None
385
386        require = None
387        if name == 'vkGetDeviceGroupSurfacePresentModes2EXT':
388            require_node = self.registry.tree.find("./extensions/extension[@name='{}']/require/command[@name='{}']/..".format(extension_name, name))
389            if 'depends' in require_node.attrib:
390                require = require_node.attrib['depends']
391
392        cmd_params = []
393
394        # Generate a list of commands for use in printing the necessary
395        # core instance terminator prototypes
396        params = cmdinfo.elem.findall('param')
397        lens = set()
398        for param in params:
399            len = self.getLen(param)
400            if len:
401                lens.add(len)
402        paramsInfo = []
403        for param in params:
404            paramInfo = self.getTypeNameTuple(param)
405            param_type = paramInfo[0]
406            param_name = paramInfo[1]
407            param_cdecl = self.makeCParamDecl(param, 0)
408            cmd_params.append(self.CommandParam(type=param_type, name=param_name,
409                                                cdecl=param_cdecl))
410
411        version = self.getAPIVersion(extension_name)
412        if version and not version.supported:
413            # Skip commands in unsupported versions
414            return
415
416        if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
417            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
418            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
419            if version:
420                self.core_commands.append(
421                    self.CommandData(name=name, ext_name=version.token,
422                                     ext_type='device',
423                                     require=require,
424                                     protect=self.featureExtraProtect,
425                                     return_type = return_type,
426                                     handle_type = handle_type,
427                                     params = cmd_params,
428                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
429            else:
430                self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
431                self.ext_commands.append(
432                    self.CommandData(name=name, ext_name=extension_name,
433                                     ext_type=extension_type,
434                                     require=require,
435                                     protect=self.featureExtraProtect,
436                                     return_type = return_type,
437                                     handle_type = handle_type,
438                                     params = cmd_params,
439                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
440        else:
441            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
442            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
443            if version:
444                self.core_commands.append(
445                    self.CommandData(name=name, ext_name=version.token,
446                                     ext_type='instance',
447                                     require=require,
448                                     protect=self.featureExtraProtect,
449                                     return_type = return_type,
450                                     handle_type = handle_type,
451                                     params = cmd_params,
452                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
453
454            else:
455                self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
456                self.ext_commands.append(
457                    self.CommandData(name=name, ext_name=extension_name,
458                                     ext_type=extension_type,
459                                     require=require,
460                                     protect=self.featureExtraProtect,
461                                     return_type = return_type,
462                                     handle_type = handle_type,
463                                     params = cmd_params,
464                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
465
466    #
467    # Retrieve the type and name for a parameter
468    def getTypeNameTuple(self, param):
469        type = ''
470        name = ''
471        for elem in param:
472            if elem.tag == 'type':
473                type = noneStr(elem.text)
474            elif elem.tag == 'name':
475                name = noneStr(elem.text)
476        return (type, name)
477
478    def OutputPrototypesInHeader(self):
479        protos = ''
480        protos += '// Structures defined externally, but used here\n'
481        protos += 'struct loader_instance;\n'
482        protos += 'struct loader_device;\n'
483        protos += 'struct loader_icd_term;\n'
484        protos += 'struct loader_dev_dispatch_table;\n'
485        protos += '\n'
486        protos += '// Device extension error function\n'
487        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev);\n'
488        protos += '\n'
489        protos += '// Extension interception for vkGetInstanceProcAddr function, so we can return\n'
490        protos += '// the appropriate information for any instance extensions we know about.\n'
491        protos += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);\n'
492        protos += '\n'
493        protos += '// Extension interception for vkCreateInstance function, so we can properly\n'
494        protos += '// detect and enable any instance extension information for extensions we know\n'
495        protos += '// about.\n'
496        protos += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);\n'
497        protos += '\n'
498        protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n'
499        protos += '// an appropriate terminator if this is one of those few device commands requiring\n'
500        protos += '// a terminator.\n'
501        protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name);\n'
502        protos += '\n'
503        protos += '// Dispatch table properly filled in with appropriate terminators for the\n'
504        protos += '// supported extensions.\n'
505        protos += 'extern const VkLayerInstanceDispatchTable instance_disp;\n'
506        protos += '\n'
507        protos += '// Array of extension strings for instance extensions we support.\n'
508        protos += 'extern const char *const LOADER_INSTANCE_EXTENSIONS[];\n'
509        protos += '\n'
510        protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term);\n'
511        protos += '\n'
512        protos += '// Init Device function pointer dispatch table with core commands\n'
513        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
514        protos += '                                                             VkDevice dev);\n'
515        protos += '\n'
516        protos += '// Init Device function pointer dispatch table with extension commands\n'
517        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
518        protos += '                                                                       PFN_vkGetInstanceProcAddr gipa,\n'
519        protos += '                                                                       PFN_vkGetDeviceProcAddr gdpa,\n'
520        protos += '                                                                       VkInstance inst,\n'
521        protos += '                                                                       VkDevice dev);\n'
522        protos += '\n'
523        protos += '// Init Instance function pointer dispatch table with core commands\n'
524        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
525        protos += '                                                                    VkInstance inst);\n'
526        protos += '\n'
527        protos += '// Init Instance function pointer dispatch table with core commands\n'
528        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
529        protos += '                                                                         VkInstance inst);\n'
530        protos += '\n'
531        protos += '// Device command lookup function\n'
532        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* name_found);\n'
533        protos += '\n'
534        protos += '// Instance command lookup function\n'
535        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
536        protos += '                                                                  bool *found_name);\n'
537        protos += '\n'
538        return protos
539
540    def OutputUtilitiesInSource(self):
541        protos = ''
542        protos += '// Device extension error function\n'
543        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev) {\n'
544        protos += '    struct loader_device *found_dev;\n'
545        protos += '    // The device going in is a trampoline device\n'
546        protos += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(dev, &found_dev, NULL);\n'
547        protos += '\n'
548        protos += '    if (icd_term)\n'
549        protos += '        loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,\n'
550        protos += '                   "Bad destination in loader trampoline dispatch,"\n'
551        protos += '                   "Are layers and extensions that you are calling enabled?");\n'
552        protos += '    return VK_ERROR_EXTENSION_NOT_PRESENT;\n'
553        protos += '}\n\n'
554        return protos
555
556    #
557    # Create a layer instance dispatch table from the appropriate list and return it as a string
558    def OutputLayerInstanceDispatchTable(self):
559        commands = []
560        table = ''
561        cur_extension_name = ''
562
563        table += '// Instance function pointer dispatch table\n'
564        table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
565
566        # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
567        # ever show up in the XML or header, so we have to manually add it.
568        table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
569        table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
570
571        for x in range(0, 2):
572            if x == 0:
573                commands = self.core_commands
574            else:
575                commands = self.ext_commands
576
577            for cur_cmd in commands:
578                version = self.getAPIVersion(cur_cmd.ext_name)
579                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
580                if is_inst_handle_type:
581
582                    if cur_cmd.ext_name != cur_extension_name:
583                        if version:
584                            table += '\n    // ---- Core %s commands\n' % version.name
585                        else:
586                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
587                        cur_extension_name = cur_cmd.ext_name
588
589                    # Remove 'vk' from proto name
590                    base_name = cur_cmd.name[2:]
591
592                    if cur_cmd.protect is not None:
593                        table += '#if defined(%s)\n' % cur_cmd.protect
594
595                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
596
597                    if cur_cmd.protect is not None:
598                        table += '#endif // %s\n' % cur_cmd.protect
599
600        table += '} VkLayerInstanceDispatchTable;\n\n'
601        return table
602
603    #
604    # Create a layer device dispatch table from the appropriate list and return it as a string
605    def OutputLayerDeviceDispatchTable(self):
606        commands = []
607        table = ''
608        cur_extension_name = ''
609
610        table += '// Device function pointer dispatch table\n'
611        table += '#define DEVICE_DISP_TABLE_MAGIC_NUMBER 0x10ADED040410ADEDUL\n'
612        table += 'typedef struct VkLayerDispatchTable_ {\n'
613        table += '    uint64_t magic; // Should be DEVICE_DISP_TABLE_MAGIC_NUMBER\n'
614
615        for x in range(0, 2):
616            if x == 0:
617                commands = self.core_commands
618            else:
619                commands = self.ext_commands
620
621            for cur_cmd in commands:
622                version = self.getAPIVersion(cur_cmd.ext_name)
623                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
624                if not is_inst_handle_type:
625
626                    if cur_cmd.ext_name != cur_extension_name:
627                        if version:
628                            table += '\n    // ---- Core %s commands\n' % version.name
629                        else:
630                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
631                        cur_extension_name = cur_cmd.ext_name
632
633                    # Remove 'vk' from proto name
634                    base_name = cur_cmd.name[2:]
635
636                    if cur_cmd.protect is not None:
637                        table += '#if defined(%s)\n' % cur_cmd.protect
638
639                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
640
641                    if cur_cmd.protect is not None:
642                        table += '#endif // %s\n' % cur_cmd.protect
643
644        table += '} VkLayerDispatchTable;\n\n'
645        return table
646
647    #
648    # Common code between the dispatch table struct and the function filling out said struct
649    def ShouldPrintInIcdDispatchTable(self, cur_cmd, skip_list):
650        return cur_cmd.name == 'vkGetDeviceProcAddr' or \
651            (cur_cmd.handle_type not in ['VkDevice', 'VkCommandBuffer', 'VkQueue'] and cur_cmd.name not in skip_list)
652
653    #
654    # Create a dispatch table from the appropriate list and return it as a string
655    def OutputIcdDispatchTable(self):
656        commands = []
657        table = ''
658        cur_extension_name = ''
659
660        skip_commands = ['vkGetInstanceProcAddr',
661                         'vkEnumerateDeviceLayerProperties',
662                        ]
663
664        table += '// ICD function pointer dispatch table\n'
665        table += 'struct loader_icd_term_dispatch {\n'
666
667        for x in range(0, 2):
668            if x == 0:
669                commands = self.core_commands
670            else:
671                commands = self.ext_commands
672
673            for cur_cmd in commands:
674                version = self.getAPIVersion(cur_cmd.ext_name)
675                if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_commands)):
676                    if cur_cmd.ext_name != cur_extension_name:
677                        if version:
678                            table += '\n    // ---- Core %s commands\n' % version.name
679                        else:
680                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
681                        cur_extension_name = cur_cmd.ext_name
682
683                    # Remove 'vk' from proto name
684                    base_name = cur_cmd.name[2:]
685
686                    if cur_cmd.protect is not None:
687                        table += '#if defined(%s)\n' % cur_cmd.protect
688
689                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
690
691                    if cur_cmd.protect is not None:
692                        table += '#endif // %s\n' % cur_cmd.protect
693
694        table += '};\n\n'
695        return table
696
697    #
698    # Init a dispatch table from the appropriate list and return it as a string
699    def OutputIcdDispatchTableInit(self):
700        commands = []
701        cur_extension_name = ''
702
703        table = ''
704        table += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term) {\n'
705        table += '    const PFN_vkGetInstanceProcAddr fp_gipa = icd_term->scanned_icd->GetInstanceProcAddr;\n'
706        table += '\n'
707        table += '#define LOOKUP_GIPA(func) icd_term->dispatch.func = (PFN_vk##func)fp_gipa(icd_term->instance, "vk" #func);\n'
708        table += '\n'
709        table += '#define LOOKUP_REQUIRED_GIPA(func)                                                      \\\n'
710        table += '    do {                                                                                \\\n'
711        table += '        LOOKUP_GIPA(func);                                                              \\\n'
712        table += '        if (!icd_term->dispatch.func) {                                                 \\\n'
713        table += '            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Unable to load %s from ICD %s",\\\n'
714        table += '                       "vk"#func, icd_term->scanned_icd->lib_name);                     \\\n'
715        table += '            return false;                                                               \\\n'
716        table += '        }                                                                               \\\n'
717        table += '    } while (0)\n'
718        table += '\n'
719
720
721        skip_gipa_commands = ['vkGetInstanceProcAddr',
722                              'vkEnumerateDeviceLayerProperties',
723                              'vkCreateInstance',
724                              'vkEnumerateInstanceExtensionProperties',
725                              'vkEnumerateInstanceLayerProperties',
726                              'vkEnumerateInstanceVersion',
727                             ]
728
729        for x in range(0, 2):
730            if x == 0:
731                commands = self.core_commands
732            else:
733                commands = self.ext_commands
734
735            required = False
736            for cur_cmd in commands:
737                version = self.getAPIVersion(cur_cmd.ext_name)
738                if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_gipa_commands)):
739
740                    if cur_cmd.ext_name != cur_extension_name:
741                        if version:
742                            table += '\n    // ---- Core %s\n' % version.name
743                            required = version.number == '1.0'
744                        else:
745                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
746                            required = False
747                        cur_extension_name = cur_cmd.ext_name
748
749                    # Remove 'vk' from proto name
750                    base_name = cur_cmd.name[2:]
751
752                    if cur_cmd.protect is not None:
753                        table += '#if defined(%s)\n' % cur_cmd.protect
754
755                    if required:
756                        # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
757                        # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
758                        table += f'    LOOKUP_REQUIRED_GIPA({base_name});\n'
759                    else:
760                        table += f'    LOOKUP_GIPA({base_name});\n'
761                    if cur_cmd.protect is not None:
762                        table += '#endif // %s\n' % cur_cmd.protect
763
764        table += '\n'
765        table += '#undef LOOKUP_REQUIRED_GIPA\n'
766        table += '#undef LOOKUP_GIPA\n'
767        table += '\n'
768        table += '    return true;\n'
769        table += '};\n\n'
770        return table
771
772    #
773    # Create the extension enable union
774    def OutputIcdExtensionEnableUnion(self):
775        extensions = self.instanceExtensions
776
777        union = ''
778        union += 'struct loader_instance_extension_enables {\n'
779        for ext in extensions:
780            if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or
781                ext.type == 'device' or ext.num_commands == 0):
782                continue
783
784            union += '    uint8_t %s;\n' % ext.name[3:].lower()
785
786        union += '};\n\n'
787        return union
788
789    #
790    # Creates the prototypes for the loader's core instance command terminators
791    def OutputLoaderTerminators(self):
792        terminators = ''
793        terminators += '// Loader core instance terminators\n'
794
795        for cur_cmd in self.core_commands:
796            is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
797            if is_inst_handle_type:
798                mod_string = ''
799                new_terminator = cur_cmd.cdecl
800                mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_")
801
802                if cur_cmd.name in PRE_INSTANCE_FUNCTIONS:
803                    mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n    const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n')
804
805                if (cur_cmd.protect is not None):
806                    terminators += '#if defined(%s)\n' % cur_cmd.protect
807
808                terminators += mod_string
809                terminators += '\n'
810
811                if (cur_cmd.protect is not None):
812                    terminators += '#endif // %s\n' % cur_cmd.protect
813
814        terminators += '\n'
815        return terminators
816
817    #
818    # Creates code to initialize the various dispatch tables
819    def OutputLoaderDispatchTables(self):
820        commands = []
821        tables = ''
822        gpa_param = ''
823        cur_type = ''
824        cur_extension_name = ''
825
826        for x in range(0, 4):
827            if x == 0:
828                cur_type = 'device'
829                gpa_param = 'dev'
830                commands = self.core_commands
831
832                tables += '// Init Device function pointer dispatch table with core commands\n'
833                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
834                tables += '                                                             VkDevice dev) {\n'
835                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
836                tables += '    if (table->magic != DEVICE_DISP_TABLE_MAGIC_NUMBER) { abort(); }\n'
837                tables += '    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch[i] = (PFN_vkDevExt)vkDevExtError;\n'
838
839            elif x == 1:
840                cur_type = 'device'
841                gpa_param = 'dev'
842                commands = self.ext_commands
843
844                tables += '// Init Device function pointer dispatch table with extension commands\n'
845                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
846                tables += '                                                                       PFN_vkGetInstanceProcAddr gipa,\n'
847                tables += '                                                                       PFN_vkGetDeviceProcAddr gdpa,\n'
848                tables += '                                                                       VkInstance inst,\n'
849                tables += '                                                                       VkDevice dev) {\n'
850                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
851                tables += '    table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n'
852
853            elif x == 2:
854                cur_type = 'instance'
855                gpa_param = 'inst'
856                commands = self.core_commands
857
858                tables += '// Init Instance function pointer dispatch table with core commands\n'
859                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
860                tables += '                                                                    VkInstance inst) {\n'
861
862            else:
863                cur_type = 'instance'
864                gpa_param = 'inst'
865                commands = self.ext_commands
866
867                tables += '// Init Instance function pointer dispatch table with core commands\n'
868                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
869                tables += '                                                                        VkInstance inst) {\n'
870
871            for cur_cmd in commands:
872                version = self.getAPIVersion(cur_cmd.ext_name)
873                is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
874                if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
875                    if cur_cmd.ext_name != cur_extension_name:
876                        if version:
877                            tables += '\n    // ---- Core %s commands\n' % version.name
878                        else:
879                            tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
880                        cur_extension_name = cur_cmd.ext_name
881
882                    # Remove 'vk' from proto name
883                    base_name = cur_cmd.name[2:]
884
885                    # Names to skip
886                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
887                        base_name == 'EnumerateInstanceExtensionProperties' or
888                        base_name == 'EnumerateInstanceLayerProperties' or
889                        base_name == 'EnumerateInstanceVersion'):
890                        continue
891
892                    if cur_cmd.protect is not None:
893                        tables += '#if defined(%s)\n' % cur_cmd.protect
894
895                    # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
896                    # a layer overrides the function name for the loader.
897                    if x == 1:
898                        if base_name == 'GetDeviceProcAddr':
899                            tables += '    table->GetDeviceProcAddr = gdpa;\n'
900                        elif cur_cmd.ext_type == 'instance':
901                            tables += '    table->%s = (PFN_%s)gipa(inst, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name)
902                        else:
903                            tables += '    table->%s = (PFN_%s)gdpa(dev, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name)
904                    elif (x < 1 and base_name == 'GetDeviceProcAddr'):
905                        tables += '    table->GetDeviceProcAddr = gpa;\n'
906                    elif (x > 1 and base_name == 'GetInstanceProcAddr'):
907                        tables += '    table->GetInstanceProcAddr = gpa;\n'
908                    else:
909                        tables += '    table->%s = (PFN_%s)gpa(%s, "%s");\n' % (base_name, cur_cmd.name, gpa_param, cur_cmd.name)
910
911                    if cur_cmd.protect is not None:
912                        tables += '#endif // %s\n' % cur_cmd.protect
913
914            tables += '}\n\n'
915        return tables
916
917    #
918    # Create a lookup table function from the appropriate list of entrypoints and
919    # return it as a string
920    def OutputLoaderLookupFunc(self):
921        commands = []
922        tables = ''
923        cur_type = ''
924        cur_extension_name = ''
925
926        for x in range(0, 2):
927            if x == 0:
928                cur_type = 'device'
929
930                tables += '// Device command lookup function\n'
931                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* found_name) {\n'
932                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') {\n'
933                tables += '        *found_name = false;\n'
934                tables += '        return NULL;\n'
935                tables += '    }\n'
936                tables += '\n'
937                tables += '    name += 2;\n'
938                tables += '    *found_name = true;\n'
939                tables += '    struct loader_device* dev = (struct loader_device *)table;\n'
940                tables += '    const struct loader_instance* inst = dev->phys_dev_term->this_icd_term->this_instance;\n'
941                tables += '    uint32_t api_version = VK_MAKE_API_VERSION(0, inst->app_api_version.major, inst->app_api_version.minor, inst->app_api_version.patch);\n'
942                tables += '\n'
943            else:
944                cur_type = 'instance'
945
946                tables += '// Instance command lookup function\n'
947                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
948                tables += '                                                                 bool *found_name) {\n'
949                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') {\n'
950                tables += '        *found_name = false;\n'
951                tables += '        return NULL;\n'
952                tables += '    }\n'
953                tables += '\n'
954                tables += '    *found_name = true;\n'
955                tables += '    name += 2;\n'
956
957
958            for y in range(0, 2):
959                if y == 0:
960                    commands = self.core_commands
961                else:
962                    commands = self.ext_commands
963
964                for cur_cmd in commands:
965                    version = self.getAPIVersion(cur_cmd.ext_name)
966                    is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
967                    if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
968                        if cur_cmd.ext_name != cur_extension_name:
969                            if version:
970                                tables += '\n    // ---- Core %s commands\n' % version.name
971                                if cur_type == 'device':
972                                    version_check = f'        if (dev->should_ignore_device_commands_from_newer_version && api_version < {version.constant}) return NULL;\n'
973                            else:
974
975                                tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
976                                version_check = ''
977                            cur_extension_name = cur_cmd.ext_name
978
979                        # Remove 'vk' from proto name
980                        base_name = cur_cmd.name[2:]
981
982                        if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
983                            base_name == 'EnumerateInstanceExtensionProperties' or
984                            base_name == 'EnumerateInstanceLayerProperties' or
985                            base_name == 'EnumerateInstanceVersion'):
986                            continue
987
988                        if cur_cmd.protect is not None:
989                            tables += '#if defined(%s)\n' % cur_cmd.protect
990
991                        tables += f'    if (!strcmp(name, "{base_name}")) '
992                        if cur_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP:
993                            if version_check != '':
994                                tables += f'{{\n{version_check}        return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n    }}\n'
995                            else:
996                                tables += f'return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n'
997
998                        else:
999                            if version_check != '':
1000                                tables += f'{{\n{version_check}        return (void *)table->{base_name};\n    }}\n'
1001                            else:
1002                                tables += f'return (void *)table->{base_name};\n'
1003
1004                        if cur_cmd.protect is not None:
1005                            tables += '#endif // %s\n' % cur_cmd.protect
1006
1007            tables += '\n'
1008            tables += '    *found_name = false;\n'
1009            tables += '    return NULL;\n'
1010            tables += '}\n\n'
1011        return tables
1012
1013    #
1014    # Create the appropriate trampoline (and possibly terminator) functions
1015    def CreateTrampTermFuncs(self):
1016        entries = []
1017        funcs = ''
1018        cur_extension_name = ''
1019
1020        # Some extensions have to be manually added.  Skip those in the automatic
1021        # generation.  They will be manually added later.
1022        manual_ext_commands = ['vkEnumeratePhysicalDeviceGroupsKHR',
1023                               'vkGetPhysicalDeviceExternalImageFormatPropertiesNV',
1024                               'vkGetPhysicalDeviceFeatures2KHR',
1025                               'vkGetPhysicalDeviceProperties2KHR',
1026                               'vkGetPhysicalDeviceFormatProperties2KHR',
1027                               'vkGetPhysicalDeviceImageFormatProperties2KHR',
1028                               'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
1029                               'vkGetPhysicalDeviceMemoryProperties2KHR',
1030                               'vkGetPhysicalDeviceSparseImageFormatProperties2KHR',
1031                               'vkGetPhysicalDeviceSurfaceCapabilities2KHR',
1032                               'vkGetPhysicalDeviceSurfaceFormats2KHR',
1033                               'vkGetPhysicalDeviceSurfaceCapabilities2EXT',
1034                               'vkReleaseDisplayEXT',
1035                               'vkAcquireXlibDisplayEXT',
1036                               'vkGetRandROutputDisplayEXT',
1037                               'vkGetPhysicalDeviceExternalBufferPropertiesKHR',
1038                               'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR',
1039                               'vkGetPhysicalDeviceExternalFencePropertiesKHR',
1040                               'vkGetPhysicalDeviceDisplayProperties2KHR',
1041                               'vkGetPhysicalDeviceDisplayPlaneProperties2KHR',
1042                               'vkGetDisplayModeProperties2KHR',
1043                               'vkGetDisplayPlaneCapabilities2KHR',
1044                               'vkGetPhysicalDeviceSurfacePresentModes2EXT',
1045                               'vkGetDeviceGroupSurfacePresentModes2EXT',
1046                               'vkGetPhysicalDeviceToolPropertiesEXT']
1047
1048        for ext_cmd in self.ext_commands:
1049            if (ext_cmd.ext_name in WSI_EXT_NAMES or
1050                ext_cmd.ext_name in AVOID_EXT_NAMES or
1051                ext_cmd.name in AVOID_CMD_NAMES or
1052                ext_cmd.name in manual_ext_commands):
1053                continue
1054
1055            version = self.getAPIVersion(ext_cmd.ext_name)
1056            if ext_cmd.ext_name != cur_extension_name:
1057                if version:
1058                    funcs += '\n// ---- Core %s trampoline/terminators\n\n' % version.name
1059                else:
1060                    funcs += '\n// ---- %s extension trampoline/terminators\n\n' % ext_cmd.ext_name
1061                cur_extension_name = ext_cmd.ext_name
1062
1063            if ext_cmd.protect is not None:
1064                funcs += '#if defined(%s)\n' % ext_cmd.protect
1065
1066            func_header = ext_cmd.cdecl.replace(";", " {\n")
1067            tramp_header = func_header.replace("VKAPI_CALL vk", "VKAPI_CALL ")
1068            return_prefix = '    '
1069            base_name = ext_cmd.name[2:]
1070            has_surface = 0
1071            update_structure_surface = 0
1072            update_structure_string = ''
1073            requires_terminator = 0
1074            surface_var_name = ''
1075            phys_dev_var_name = ''
1076            instance_var_name = ''
1077            has_return_type = False
1078            always_use_param_name = True
1079            surface_type_to_replace = ''
1080            surface_name_replacement = ''
1081            physdev_type_to_replace = ''
1082            physdev_name_replacement = ''
1083
1084            for param in ext_cmd.params:
1085                if param.type == 'VkSurfaceKHR':
1086                    has_surface = 1
1087                    surface_var_name = param.name
1088                    requires_terminator = 1
1089                    always_use_param_name = False
1090                    surface_type_to_replace = 'VkSurfaceKHR'
1091                    surface_name_replacement = 'icd_surface->real_icd_surfaces[icd_index]'
1092                if param.type == 'VkPhysicalDeviceSurfaceInfo2KHR':
1093                    has_surface = 1
1094                    surface_var_name = param.name + '->surface'
1095                    requires_terminator = 1
1096                    update_structure_surface = 1
1097                    update_structure_string = '        VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;\n'
1098                    update_structure_string += '        info_copy.surface = icd_surface->real_icd_surfaces[icd_index];\n'
1099                    always_use_param_name = False
1100                    surface_type_to_replace = 'VkPhysicalDeviceSurfaceInfo2KHR'
1101                    surface_name_replacement = '&info_copy'
1102                if param.type == 'VkPhysicalDevice':
1103                    requires_terminator = 1
1104                    phys_dev_var_name = param.name
1105                    always_use_param_name = False
1106                    physdev_type_to_replace = 'VkPhysicalDevice'
1107                    physdev_name_replacement = 'phys_dev_term->phys_dev'
1108                if param.type == 'VkInstance':
1109                    requires_terminator = 1
1110                    instance_var_name = param.name
1111
1112            if (ext_cmd.return_type is not None):
1113                return_prefix += 'return '
1114                has_return_type = True
1115
1116            if (ext_cmd.handle_type == 'VkInstance' or ext_cmd.handle_type == 'VkPhysicalDevice' or
1117                'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or
1118                ext_cmd.name in DEVICE_CMDS_NEED_TERM):
1119                requires_terminator = 1
1120
1121            if requires_terminator == 1:
1122                term_header = tramp_header.replace("VKAPI_CALL ", "VKAPI_CALL terminator_")
1123
1124                funcs += tramp_header
1125
1126                if ext_cmd.handle_type == 'VkPhysicalDevice':
1127                    funcs += '    const VkLayerInstanceDispatchTable *disp;\n'
1128                    funcs += '    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(%s);\n' % (phys_dev_var_name)
1129                    funcs += '    if (VK_NULL_HANDLE == unwrapped_phys_dev) {\n'
1130                    funcs += '        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n'
1131                    funcs += '                   "%s: Invalid %s "\n' % (ext_cmd.name, phys_dev_var_name)
1132                    funcs += '                   "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, phys_dev_var_name)
1133                    funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1134                    funcs += '    }\n'
1135                    funcs += '    disp = loader_get_instance_layer_dispatch(%s);\n' % (phys_dev_var_name)
1136                elif ext_cmd.handle_type == 'VkInstance':
1137                    funcs += '    struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name)
1138                    funcs += '    if (NULL == inst) {\n'
1139                    funcs += '        loader_log(\n'
1140                    funcs += '            NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n'
1141                    funcs += '            "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name)
1142                    funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1143                    funcs += '    }\n'
1144                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
1145                else:
1146                    funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
1147                    funcs += ext_cmd.params[0].name
1148                    funcs += ');\n'
1149                    funcs += '    if (NULL == disp) {\n'
1150                    funcs += '        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n'
1151                    funcs += '                   "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name)
1152                    funcs += '                   "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name)
1153                    funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1154                    funcs += '    }\n'
1155
1156                if 'DebugMarkerSetObjectName' in ext_cmd.name:
1157                    funcs += '    VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
1158                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
1159                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1160                    funcs += '    if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
1161                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->object;\n'
1162                    funcs += '        local_name_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
1163                    funcs += '    }\n'
1164                    funcs += '    if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n'
1165                    funcs += '        struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->object;\n'
1166                    funcs += '        local_name_info.object = (uint64_t)(uintptr_t)instance->instance;\n'
1167                    funcs += '    }\n'
1168                elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
1169                    funcs += '    VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
1170                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
1171                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1172                    funcs += '    if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
1173                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n'
1174                    funcs += '        local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
1175                    funcs += '    }\n'
1176                    funcs += '    if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n'
1177                    funcs += '        struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->object;\n'
1178                    funcs += '        local_tag_info.object = (uint64_t)(uintptr_t)instance->instance;\n'
1179                    funcs += '    }\n'
1180                elif 'SetDebugUtilsObjectName' in ext_cmd.name:
1181                    funcs += '    VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
1182                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
1183                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1184                    funcs += '    if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
1185                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->objectHandle;\n'
1186                    funcs += '        local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
1187                    funcs += '    }\n'
1188                    funcs += '    if (pNameInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n'
1189                    funcs += '        struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->objectHandle;\n'
1190                    funcs += '        local_name_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n'
1191                    funcs += '    }\n'
1192                elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
1193                    funcs += '    VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
1194                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
1195                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1196                    funcs += '    if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
1197                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->objectHandle;\n'
1198                    funcs += '        local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
1199                    funcs += '    }\n'
1200                    funcs += '    if (pTagInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n'
1201                    funcs += '        struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->objectHandle;\n'
1202                    funcs += '        local_tag_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n'
1203                    funcs += '    }\n'
1204
1205                if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES:
1206                    funcs += '    if (disp->' + base_name + ' != NULL) {\n'
1207                    funcs += '    '
1208                funcs += return_prefix
1209                if ext_cmd.handle_type == 'VkInstance':
1210                    funcs += 'inst->'
1211                funcs += 'disp->'
1212                funcs += base_name
1213                funcs += '('
1214                count = 0
1215                for param in ext_cmd.params:
1216                    if count != 0:
1217                        funcs += ', '
1218
1219                    if param.type == 'VkPhysicalDevice':
1220                        funcs += 'unwrapped_phys_dev'
1221                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
1222                            funcs += '&local_name_info'
1223                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
1224                            funcs += '&local_tag_info'
1225                    else:
1226                        funcs += param.name
1227
1228                    count += 1
1229                funcs += ');\n'
1230                if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES:
1231                    if ext_cmd.return_type is not None:
1232                        funcs += '    } else {\n'
1233                        funcs += '        return VK_SUCCESS;\n'
1234                    funcs += '    }\n'
1235                funcs += '}\n\n'
1236
1237                funcs += term_header
1238                if ext_cmd.handle_type == 'VkPhysicalDevice':
1239                    funcs += '    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)%s;\n' % (phys_dev_var_name)
1240                    funcs += '    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;\n'
1241                    funcs += '    if (NULL == icd_term->dispatch.'
1242                    funcs += base_name
1243                    funcs += ') {\n'
1244                    fatal_error_bit = '' if ext_cmd.ext_type =='instance' and has_return_type else 'VULKAN_LOADER_FATAL_ERROR_BIT | '
1245                    funcs += f'        loader_log(icd_term->this_instance, {fatal_error_bit}VULKAN_LOADER_ERROR_BIT, 0,\n'
1246                    funcs += '                   "ICD associated with VkPhysicalDevice does not support '
1247                    funcs += base_name
1248                    funcs += '");\n'
1249
1250                    # If this is an instance function taking a physical device (i.e. pre Vulkan 1.1), we need to behave and not crash so return an
1251                    # error here.
1252                    if ext_cmd.ext_type =='instance' and has_return_type:
1253                        funcs += '        return VK_ERROR_EXTENSION_NOT_PRESENT;\n'
1254                    else:
1255                        funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1256                    funcs += '    }\n'
1257
1258                    if has_surface == 1:
1259                        funcs += '    VkIcdSurface *icd_surface = (VkIcdSurface *)(%s);\n' % (surface_var_name)
1260                        funcs += '    uint8_t icd_index = phys_dev_term->icd_index;\n'
1261                        funcs += '    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)icd_surface->real_icd_surfaces[icd_index]) {\n'
1262
1263                        # If there's a structure with a surface, we need to update its internals with the correct surface for the ICD
1264                        if update_structure_surface == 1:
1265                            funcs += update_structure_string
1266
1267                        funcs += '    ' + return_prefix + 'icd_term->dispatch.'
1268                        funcs += base_name
1269                        funcs += '('
1270                        count = 0
1271                        for param in ext_cmd.params:
1272                            if count != 0:
1273                                funcs += ', '
1274
1275                            if not always_use_param_name:
1276                                if surface_type_to_replace and surface_type_to_replace == param.type:
1277                                    funcs += surface_name_replacement
1278                                elif physdev_type_to_replace and physdev_type_to_replace == param.type:
1279                                    funcs += physdev_name_replacement
1280                                else:
1281                                    funcs += param.name
1282                            else:
1283                                funcs += param.name
1284
1285                            count += 1
1286                        funcs += ');\n'
1287                        if not has_return_type:
1288                            funcs += '        return;\n'
1289                        funcs += '    }\n'
1290
1291                    funcs += return_prefix
1292                    funcs += 'icd_term->dispatch.'
1293                    funcs += base_name
1294                    funcs += '('
1295                    count = 0
1296                    for param in ext_cmd.params:
1297                        if count != 0:
1298                            funcs += ', '
1299
1300                        if param.type == 'VkPhysicalDevice':
1301                            funcs += 'phys_dev_term->phys_dev'
1302                        else:
1303                            funcs += param.name
1304
1305                        count += 1
1306                    funcs += ');\n'
1307
1308
1309                elif ext_cmd.handle_type == 'VkInstance':
1310                    funcs += '    struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name)
1311                    funcs += '    if (NULL == inst) {\n'
1312                    funcs += '        loader_log(\n'
1313                    funcs += '            NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n'
1314                    funcs += '            "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name)
1315                    funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1316                    funcs += '    }\n'
1317                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
1318                elif ext_cmd.ext_name in ['VK_EXT_debug_utils', 'VK_EXT_debug_marker']:
1319                    if ext_cmd.name in ['vkDebugMarkerSetObjectNameEXT', 'vkDebugMarkerSetObjectTagEXT', 'vkSetDebugUtilsObjectNameEXT' , 'vkSetDebugUtilsObjectTagEXT']:
1320
1321                        is_debug_utils = ext_cmd.ext_name == "VK_EXT_debug_utils"
1322                        debug_struct_name = ext_cmd.params[1].name
1323                        local_struct = 'local_name_info' if 'ObjectName' in ext_cmd.name else 'local_tag_info'
1324                        member_name = 'objectHandle' if is_debug_utils else 'object'
1325                        phys_dev_check = 'VK_OBJECT_TYPE_PHYSICAL_DEVICE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT'
1326                        surf_check = 'VK_OBJECT_TYPE_SURFACE_KHR' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT'
1327                        inst_check = 'VK_OBJECT_TYPE_INSTANCE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT'
1328                        funcs += '    uint32_t icd_index = 0;\n'
1329                        funcs += '    struct loader_device *dev;\n'
1330                        funcs += f'    struct loader_icd_term *icd_term = loader_get_icd_and_device({ ext_cmd.params[0].name}, &dev, &icd_index);\n'
1331                        funcs += f'    if (NULL == icd_term || NULL == dev) {{\n'
1332                        funcs += f'        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.name[2:]}: Invalid device handle");\n'
1333                        funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1334                        funcs += '    }\n'
1335                        funcs += f'    { ext_cmd.params[1].type} {local_struct};\n'
1336                        funcs += f'    memcpy(&{local_struct}, {debug_struct_name}, sizeof({ ext_cmd.params[1].type}));\n'
1337                        funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1338                        funcs += f'    if ({debug_struct_name}->objectType == {phys_dev_check}) {{\n'
1339                        funcs += f'        struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t){debug_struct_name}->{member_name};\n'
1340                        funcs += f'        {local_struct}.{member_name} = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
1341                        funcs += '    // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
1342                        funcs += f'    }} else if ({debug_struct_name}->objectType == {surf_check}) {{\n'
1343                        funcs += '        if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {\n'
1344                        funcs += f'            VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t){debug_struct_name}->{member_name};\n'
1345                        funcs += '            if (NULL != icd_surface->real_icd_surfaces) {\n'
1346                        funcs += f'                {local_struct}.{member_name} = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
1347                        funcs += '            }\n'
1348                        funcs += '        }\n'
1349                        funcs += '    // If this is an instance we have to replace it with the proper one for the next call.\n'
1350                        funcs += f'    }} else if ({debug_struct_name}->objectType == {inst_check}) {{\n'
1351                        funcs += f'        {local_struct}.{member_name} = (uint64_t)(uintptr_t)icd_term->instance;\n'
1352                        funcs += '    }\n'
1353                        funcs += '    // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports\n'
1354                        funcs += '    // debug utils but the driver does not.\n'
1355                        funcs += f'    if (NULL == dev->loader_dispatch.extension_terminator_dispatch.{ext_cmd.name[2:]})\n        return VK_SUCCESS;\n'
1356                        dispatch = 'dev->loader_dispatch.'
1357                    else:
1358                        funcs += f'    struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch({ext_cmd.params[0].name});\n'
1359                        funcs += f'    if (NULL == dispatch_table) {{\n'
1360                        funcs += f'        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.ext_name}: Invalid device handle");\n'
1361                        funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1362                        funcs += '    }\n'
1363                        funcs += '    // Only call down if the device supports the function\n'
1364                        funcs += f'    if (NULL != dispatch_table->extension_terminator_dispatch.{base_name})\n    '
1365                        dispatch = 'dispatch_table->'
1366                    funcs += '    '
1367                    if has_return_type:
1368                        funcs += 'return '
1369                    funcs += f'{dispatch}extension_terminator_dispatch.{base_name}('
1370                    count = 0
1371                    for param in ext_cmd.params:
1372                        if count != 0:
1373                            funcs += ', '
1374
1375                        if param.type == 'VkPhysicalDevice':
1376                            funcs += 'phys_dev_term->phys_dev'
1377                        elif param.type == 'VkSurfaceKHR':
1378                            funcs += 'icd_surface->real_icd_surfaces[icd_index]'
1379                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
1380                            funcs += '&local_name_info'
1381                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
1382                            funcs += '&local_tag_info'
1383                        else:
1384                            funcs += param.name
1385                        count += 1
1386
1387                    funcs += ');\n'
1388
1389                else:
1390                    funcs += '#error("Unknown error path!");\n'
1391
1392                funcs += '}\n\n'
1393            else:
1394                funcs += tramp_header
1395
1396                funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
1397                funcs += ext_cmd.params[0].name
1398                funcs += ');\n'
1399                funcs += '    if (NULL == disp) {\n'
1400                funcs += '        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n'
1401                funcs += '                   "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name)
1402                funcs += '                   "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name)
1403                funcs += '        abort(); /* Intentionally fail so user can correct issue. */\n'
1404                funcs += '    }\n'
1405
1406                if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES:
1407                    funcs += '    if (disp->' + base_name + ' != NULL) {\n'
1408                    funcs += '    '
1409                funcs += return_prefix
1410                funcs += 'disp->'
1411                funcs += base_name
1412                funcs += '('
1413                count = 0
1414                for param in ext_cmd.params:
1415                    if count != 0:
1416                        funcs += ', '
1417                    funcs += param.name
1418                    count += 1
1419                funcs += ');\n'
1420                if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES:
1421                    if ext_cmd.return_type is not None:
1422                        funcs += '    } else {\n'
1423                        funcs += '        return VK_SUCCESS;\n'
1424                    funcs += '    }\n'
1425                funcs += '}\n\n'
1426
1427            if ext_cmd.protect is not None:
1428                funcs += '#endif // %s\n' % ext_cmd.protect
1429
1430        return funcs
1431
1432
1433    #
1434    # Create a function for the extension GPA call
1435    def InstExtensionGPA(self):
1436        entries = []
1437        gpa_func = ''
1438        cur_extension_name = ''
1439
1440        gpa_func += '// GPA helpers for extensions\n'
1441        gpa_func += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {\n'
1442        gpa_func += '    *addr = NULL;\n\n'
1443
1444        for cur_cmd in self.ext_commands:
1445            if (self.getAPIVersion(cur_cmd.ext_name) or
1446                cur_cmd.ext_name in WSI_EXT_NAMES or
1447                cur_cmd.ext_name in AVOID_EXT_NAMES or
1448                cur_cmd.name in AVOID_CMD_NAMES ):
1449                continue
1450
1451            if cur_cmd.ext_name != cur_extension_name:
1452                gpa_func += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
1453                cur_extension_name = cur_cmd.ext_name
1454
1455            if cur_cmd.protect is not None:
1456                gpa_func += '#if defined(%s)\n' % cur_cmd.protect
1457
1458            #base_name = cur_cmd.name[2:]
1459            base_name = SHARED_ALIASES[cur_cmd.name] if cur_cmd.name in SHARED_ALIASES else cur_cmd.name[2:]
1460
1461            if (cur_cmd.ext_type == 'instance'):
1462                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
1463                gpa_func += '        *addr = (ptr_instance->enabled_known_extensions.'
1464                gpa_func += cur_cmd.ext_name[3:].lower()
1465                gpa_func += ' == 1)\n'
1466                gpa_func += '                     ? (void *)%s\n' % (base_name)
1467                gpa_func += '                     : NULL;\n'
1468                gpa_func += '        return true;\n'
1469                gpa_func += '    }\n'
1470            else:
1471                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
1472                gpa_func += '        *addr = (void *)%s;\n' % (base_name)
1473                gpa_func += '        return true;\n'
1474                gpa_func += '    }\n'
1475
1476            if cur_cmd.protect is not None:
1477                gpa_func += '#endif // %s\n' % cur_cmd.protect
1478
1479        gpa_func += '    return false;\n'
1480        gpa_func += '}\n\n'
1481
1482        return gpa_func
1483
1484    #
1485    # Create the extension name init function
1486    def InstantExtensionCreate(self):
1487        entries = []
1488        entries = self.instanceExtensions
1489        count = 0
1490        cur_extension_name = ''
1491
1492        create_func = ''
1493        create_func += '// A function that can be used to query enabled extensions during a vkCreateInstance call\n'
1494        create_func += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {\n'
1495        create_func += '    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n'
1496        for ext in entries:
1497            if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or
1498                ext.name in AVOID_EXT_NAMES or ext.name in AVOID_CMD_NAMES or
1499                ext.type == 'device' or ext.num_commands == 0):
1500                continue
1501
1502            if ext.name != cur_extension_name:
1503                create_func += '\n    // ---- %s extension commands\n' % ext.name
1504                cur_extension_name = ext.name
1505
1506            if ext.protect is not None:
1507                create_func += '#if defined(%s)\n' % ext.protect
1508            if count == 0:
1509                create_func += '        if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
1510            else:
1511                create_func += '        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
1512
1513            create_func += ext.define + ')) {\n'
1514            create_func += '            ptr_instance->enabled_known_extensions.'
1515            create_func += ext.name[3:].lower()
1516            create_func += ' = 1;\n'
1517
1518            if ext.protect is not None:
1519                create_func += '#endif // %s\n' % ext.protect
1520            count += 1
1521
1522        create_func += '        }\n'
1523        create_func += '    }\n'
1524        create_func += '}\n\n'
1525        return create_func
1526
1527    #
1528    # Create code to initialize a dispatch table from the appropriate list of
1529    # extension entrypoints and return it as a string
1530    def DeviceExtensionGetTerminator(self):
1531        term_func = ''
1532
1533        term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n'
1534        term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object.  But there may be other items\n'
1535        term_func += '// in the future.\n'
1536        term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name) {\n'
1537        term_func += '''    *found_name = false;
1538    if (!name || name[0] != 'v' || name[1] != 'k') {
1539        return NULL;
1540    }
1541    name += 2;
1542'''
1543        last_protect = None
1544        last_ext = None
1545        for ext_cmd in self.ext_commands:
1546            version = self.getAPIVersion(ext_cmd.ext_name)
1547            if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
1548                if version:
1549                    term_func += f'    // ---- Core {version.name} commands\n'
1550                else:
1551                    last_protect = ext_cmd.protect
1552                    if ext_cmd.protect is not None:
1553                        term_func += f'#if defined({ext_cmd.protect})\n'
1554                    if (last_ext != ext_cmd.ext_name):
1555                        term_func += f'    // ---- {ext_cmd.ext_name} extension commands\n'
1556                        last_ext = ext_cmd.ext_name
1557
1558                term_func += f'    if (!strcmp(name, "{ext_cmd.name[2:]}")) {{\n'
1559                term_func += f'        *found_name = true;\n'
1560                if ext_cmd.require:
1561                    term_func += f'        return dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->driver_extensions.{ext_cmd.require[3:].lower()}_enabled ?\n'
1562                else:
1563                    term_func += f'        return dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled ?\n'
1564                term_func += f'            (PFN_vkVoidFunction)terminator_{(ext_cmd.name[2:])} : NULL;\n'
1565                term_func += f'    }}\n'
1566
1567        if last_protect is not None:
1568            term_func += '#endif // %s\n' % last_protect
1569
1570        term_func += '    return NULL;\n'
1571        term_func += '}\n\n'
1572
1573        return term_func
1574
1575    #
1576    # Create a dispatch table solely for device functions which have custom terminators
1577    def OutputDeviceFunctionTerminatorDispatchTable(self):
1578        term_func = ''
1579        term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n'
1580        term_func += '// device function. This is used in the terminators themselves.\n'
1581        term_func += 'struct loader_device_terminator_dispatch {\n'
1582
1583        last_protect = None
1584        last_ext = None
1585        for ext_cmd in self.ext_commands:
1586            version = self.getAPIVersion(ext_cmd.ext_name)
1587            if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
1588                if version:
1589                    term_func += f'    // ---- Core {version.name} commands\n'
1590                else:
1591                    last_protect = ext_cmd.protect
1592                    if ext_cmd.protect is not None:
1593                        term_func += f'#if defined({ext_cmd.protect})\n'
1594                    if (last_ext != ext_cmd.ext_name):
1595                        term_func += f'    // ---- {ext_cmd.ext_name} extension commands\n'
1596                        last_ext = ext_cmd.ext_name
1597
1598                term_func += f'    PFN_{ext_cmd.name} {ext_cmd.name[2:]};\n'
1599
1600        if last_protect is not None:
1601            term_func += '#endif // %s\n' % last_protect
1602
1603        term_func += '};\n\n'
1604
1605        return term_func
1606
1607    def OutputDeviceFunctionTrampolinePrototypes(self):
1608        tramp_protos = ''
1609        tramp_protos += '// These are prototypes for functions that need their trampoline called in all circumstances.\n'
1610        tramp_protos += '// They are used in loader_lookup_device_dispatch_table but are defined afterwards.\n'
1611        last_protect = None
1612        last_ext = None
1613        for ext_cmd in self.ext_commands:
1614            version = self.getAPIVersion(ext_cmd.ext_name)
1615            if ext_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP:
1616                if version:
1617                    tramp_protos += f'    // ---- Core {version.name} commands\n'
1618                else:
1619                    last_protect = ext_cmd.protect
1620                    if ext_cmd.protect is not None:
1621                        tramp_protos += f'#if defined({ext_cmd.protect})\n'
1622                    if (last_ext != ext_cmd.ext_name):
1623                        tramp_protos += f'    // ---- {ext_cmd.ext_name} extension commands\n'
1624                        last_ext = ext_cmd.ext_name
1625
1626                tramp_protos += f'{ext_cmd.cdecl.replace("VKAPI_CALL vk", "VKAPI_CALL ")}\n'
1627
1628        if last_protect is not None:
1629            tramp_protos += '#endif // %s\n' % last_protect
1630        tramp_protos += '\n'
1631        return tramp_protos
1632
1633    #
1634    # Create code to initialize a dispatch table from the appropriate list of
1635    # extension entrypoints and return it as a string
1636    def InitDeviceFunctionTerminatorDispatchTable(self):
1637        term_func = ''
1638
1639        term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n'
1640        term_func += '// device function. This is used in the terminators themselves.\n'
1641        term_func += 'void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {\n'
1642        term_func += '    struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;\n'
1643        term_func += '    PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;\n'
1644        last_protect = None
1645        last_ext = None
1646        for ext_cmd in self.ext_commands:
1647            version = self.getAPIVersion(ext_cmd.ext_name)
1648            if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
1649                if version:
1650                    term_func += f'    // ---- Core {version.name} commands\n'
1651                else:
1652                    last_protect = ext_cmd.protect
1653                    if ext_cmd.protect is not None:
1654                        term_func += f'#if defined({ext_cmd.protect})\n'
1655                    if (last_ext != ext_cmd.ext_name):
1656                        term_func += f'    // ---- {ext_cmd.ext_name} extension commands\n'
1657                        last_ext = ext_cmd.ext_name
1658
1659
1660                if ext_cmd.require:
1661                    term_func += f'    if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->driver_extensions.{ext_cmd.require[3:].lower()}_enabled)\n'
1662                    term_func += f'       dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
1663                else:
1664                    term_func += f'    if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled)\n'
1665                    term_func += f'       dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n'
1666
1667        if last_protect is not None:
1668            term_func += '#endif // %s\n' % last_protect
1669
1670        term_func += '}\n\n'
1671
1672        return term_func
1673
1674    #
1675    # Create code to initialize a dispatch table from the appropriate list of
1676    # core and extension entrypoints and return it as a string
1677    def InitInstLoaderExtensionDispatchTable(self):
1678        commands = []
1679        table = ''
1680        cur_extension_name = ''
1681
1682        table += '// This table contains the loader\'s instance dispatch table, which contains\n'
1683        table += '// default functions if no instance layers are activated.  This contains\n'
1684        table += '// pointers to "terminator functions".\n'
1685        table += 'const VkLayerInstanceDispatchTable instance_disp = {\n'
1686
1687        for x in range(0, 2):
1688            if x == 0:
1689                commands = self.core_commands
1690            else:
1691                commands = self.ext_commands
1692
1693            for cur_cmd in commands:
1694                version = self.getAPIVersion(cur_cmd.ext_name)
1695                if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice':
1696                    if cur_cmd.ext_name != cur_extension_name:
1697                        if version:
1698                            table += '\n    // ---- Core %s commands\n' % version.name
1699                        else:
1700                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
1701                        cur_extension_name = cur_cmd.ext_name
1702
1703                    # Remove 'vk' from proto name
1704                    base_name = cur_cmd.name[2:]
1705                    aliased_name = SHARED_ALIASES[cur_cmd.name][2:] if cur_cmd.name in SHARED_ALIASES else base_name
1706
1707                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
1708                        base_name == 'EnumerateInstanceExtensionProperties' or
1709                        base_name == 'EnumerateInstanceLayerProperties' or
1710                        base_name == 'EnumerateInstanceVersion'):
1711                        continue
1712
1713                    if cur_cmd.protect is not None:
1714                        table += '#if defined(%s)\n' % cur_cmd.protect
1715
1716                    if base_name == 'GetInstanceProcAddr':
1717                        table += '    .%s = %s,\n' % (base_name, cur_cmd.name)
1718                    else:
1719                        table += '    .%s = terminator_%s,\n' % (base_name, aliased_name)
1720
1721                    if cur_cmd.protect is not None:
1722                        table += '#endif // %s\n' % cur_cmd.protect
1723        table += '};\n\n'
1724
1725        return table
1726
1727    #
1728    # Create the extension name whitelist array
1729    def OutputInstantExtensionWhitelistArray(self):
1730        extensions = self.instanceExtensions
1731
1732        table = ''
1733        table += '// A null-terminated list of all of the instance extensions supported by the loader.\n'
1734        table += '// If an instance extension name is not in this list, but it is exported by one or more of the\n'
1735        table += '// ICDs detected by the loader, then the extension name not in the list will be filtered out\n'
1736        table += '// before passing the list of extensions to the application.\n'
1737        table += 'const char *const LOADER_INSTANCE_EXTENSIONS[] = {\n'
1738        for ext in extensions:
1739            if ext.type == 'device' or self.getAPIVersion(ext.name):
1740                continue
1741
1742            if ext.protect is not None:
1743                table += '#if defined(%s)\n' % ext.protect
1744            table += '                                                  '
1745            table += ext.define + ',\n'
1746
1747            if ext.protect is not None:
1748                table += '#endif // %s\n' % ext.protect
1749        table += '                                                  NULL };\n'
1750        return table
1751
1752