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