1#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2017 The Khronos Group Inc.
4# Copyright (c) 2015-2017 Valve Corporation
5# Copyright (c) 2015-2017 LunarG, Inc.
6# Copyright (c) 2015-2017 Google Inc.
7#
8# Licensed under the Apache License, Version 2.0 (the "License");
9# you may not use this file except in compliance with the License.
10# You may obtain a copy of the License at
11#
12#     http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS,
16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17# See the License for the specific language governing permissions and
18# limitations under the License.
19#
20# Author: Mark Young <marky@lunarg.com>
21
22import os,re,sys
23import xml.etree.ElementTree as etree
24from generator import *
25from collections import namedtuple
26
27WSI_EXT_NAMES = ['VK_KHR_surface',
28                 'VK_KHR_display',
29                 'VK_KHR_xlib_surface',
30                 'VK_KHR_xcb_surface',
31                 'VK_KHR_wayland_surface',
32                 'VK_KHR_mir_surface',
33                 'VK_KHR_win32_surface',
34                 'VK_KHR_android_surface',
35                 'VK_KHR_swapchain',
36                 'VK_KHR_display_swapchain']
37
38AVOID_EXT_NAMES = ['VK_EXT_debug_report']
39
40DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr',
41                         'vkCreateSwapchainKHR',
42                         'vkCreateSharedSwapchainsKHR',
43                         'vkGetDeviceGroupSurfacePresentModesKHX',
44                         'vkDebugMarkerSetObjectTagEXT',
45                         'vkDebugMarkerSetObjectNameEXT']
46
47PRE_INSTANCE_FUNCTIONS = ['vkEnumerateInstanceExtensionProperties',
48                          'vkEnumerateInstanceLayerProperties']
49
50#
51# LoaderExtensionGeneratorOptions - subclass of GeneratorOptions.
52class LoaderExtensionGeneratorOptions(GeneratorOptions):
53    def __init__(self,
54                 filename = None,
55                 directory = '.',
56                 apiname = None,
57                 profile = None,
58                 versions = '.*',
59                 emitversions = '.*',
60                 defaultExtensions = None,
61                 addExtensions = None,
62                 removeExtensions = None,
63                 sortProcedure = regSortFeatures,
64                 prefixText = "",
65                 genFuncPointers = True,
66                 protectFile = True,
67                 protectFeature = True,
68                 protectProto = None,
69                 protectProtoStr = None,
70                 apicall = '',
71                 apientry = '',
72                 apientryp = '',
73                 alignFuncParam = 0,
74                 currentExtension = '',
75                 extensionOfInterest = 0):
76        GeneratorOptions.__init__(self, filename, directory, apiname, profile,
77                                  versions, emitversions, defaultExtensions,
78                                  addExtensions, removeExtensions, sortProcedure)
79        self.prefixText      = prefixText
80        self.genFuncPointers = genFuncPointers
81        self.prefixText      = None
82        self.protectFile     = protectFile
83        self.protectFeature  = protectFeature
84        self.protectProto    = protectProto
85        self.protectProtoStr = protectProtoStr
86        self.apicall         = apicall
87        self.apientry        = apientry
88        self.apientryp       = apientryp
89        self.alignFuncParam  = alignFuncParam
90#
91# LoaderExtensionOutputGenerator - subclass of OutputGenerator.
92# Generates dispatch table helper header files for LVL
93class LoaderExtensionOutputGenerator(OutputGenerator):
94    """Generate dispatch table helper header based on XML element attributes"""
95    def __init__(self,
96                 errFile = sys.stderr,
97                 warnFile = sys.stderr,
98                 diagFile = sys.stdout):
99        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
100
101        # Internal state - accumulators for different inner block text
102        self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
103        self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
104        self.core_commands = []               # List of CommandData records for core Vulkan commands
105        self.ext_commands = []                # List of CommandData records for extension Vulkan commands
106        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
107        self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
108        self.instanceExtensions = []
109        self.ExtensionData = namedtuple('ExtensionData', ['name', 'type', 'protect', 'define', 'num_commands'])
110
111    #
112    # Called once at the beginning of each run
113    def beginFile(self, genOpts):
114        OutputGenerator.beginFile(self, genOpts)
115
116        # User-supplied prefix text, if any (list of strings)
117        if (genOpts.prefixText):
118            for s in genOpts.prefixText:
119                write(s, file=self.outFile)
120
121        # File Comment
122        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
123        file_comment += '// See loader_extension_generator.py for modifications\n'
124        write(file_comment, file=self.outFile)
125
126        # Copyright Notice
127        copyright =  '/*\n'
128        copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
129        copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
130        copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
131        copyright += ' *\n'
132        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
133        copyright += ' * you may not use this file except in compliance with the License.\n'
134        copyright += ' * You may obtain a copy of the License at\n'
135        copyright += ' *\n'
136        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
137        copyright += ' *\n'
138        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
139        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
140        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
141        copyright += ' * See the License for the specific language governing permissions and\n'
142        copyright += ' * limitations under the License.\n'
143        copyright += ' *\n'
144        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
145        copyright += ' * Author: Mark Young <marky@lunarg.com>\n'
146        copyright += ' */\n'
147
148        preamble = ''
149
150        if self.genOpts.filename == 'vk_loader_extensions.h':
151            preamble += '#pragma once\n'
152
153        elif self.genOpts.filename == 'vk_loader_extensions.c':
154            preamble += '#define _GNU_SOURCE\n'
155            preamble += '#include <stdio.h>\n'
156            preamble += '#include <stdlib.h>\n'
157            preamble += '#include <string.h>\n'
158            preamble += '#include "vk_loader_platform.h"\n'
159            preamble += '#include "loader.h"\n'
160            preamble += '#include "vk_loader_extensions.h"\n'
161            preamble += '#include <vulkan/vk_icd.h>\n'
162            preamble += '#include "wsi.h"\n'
163            preamble += '#include "debug_report.h"\n'
164            preamble += '#include "extension_manual.h"\n'
165
166        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
167            preamble += '#pragma once\n'
168            preamble += '\n'
169            preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
170
171        write(copyright, file=self.outFile)
172        write(preamble, file=self.outFile)
173
174    #
175    # Write generate and write dispatch tables to output file
176    def endFile(self):
177        file_data = ''
178
179        if self.genOpts.filename == 'vk_loader_extensions.h':
180            file_data += self.OutputPrototypesInHeader()
181            file_data += self.OutputLoaderTerminators()
182            file_data += self.OutputIcdDispatchTable()
183            file_data += self.OutputIcdExtensionEnableUnion()
184
185        elif self.genOpts.filename == 'vk_loader_extensions.c':
186            file_data += self.OutputUtilitiesInSource()
187            file_data += self.OutputIcdDispatchTableInit()
188            file_data += self.OutputLoaderDispatchTables()
189            file_data += self.OutputLoaderLookupFunc()
190            file_data += self.CreateTrampTermFuncs()
191            file_data += self.InstExtensionGPA()
192            file_data += self.InstantExtensionCreate()
193            file_data += self.DeviceExtensionGetTerminator()
194            file_data += self.InitInstLoaderExtensionDispatchTable()
195            file_data += self.OutputInstantExtensionWhitelistArray()
196
197        elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
198            file_data += self.OutputLayerInstanceDispatchTable()
199            file_data += self.OutputLayerDeviceDispatchTable()
200
201        write(file_data, file=self.outFile);
202
203        # Finish processing in superclass
204        OutputGenerator.endFile(self)
205
206    def beginFeature(self, interface, emit):
207        # Start processing in superclass
208        OutputGenerator.beginFeature(self, interface, emit)
209
210        enums = interface[0].findall('enum')
211        self.currentExtension = ''
212        self.name_definition = ''
213
214        for item in enums:
215            name_definition = item.get('name')
216            if 'EXTENSION_NAME' in name_definition:
217                self.name_definition = name_definition
218
219        self.type = interface.get('type')
220        self.num_commands = 0
221        name = interface.get('name')
222        self.currentExtension = name
223
224    #
225    # Process commands, adding to appropriate dispatch tables
226    def genCmd(self, cmdinfo, name):
227        OutputGenerator.genCmd(self, cmdinfo, name)
228
229        # Get first param type
230        params = cmdinfo.elem.findall('param')
231        info = self.getTypeNameTuple(params[0])
232
233        self.num_commands += 1
234
235        if 'android' not in name:
236            self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
237
238    def endFeature(self):
239
240        if 'android' not in self.currentExtension:
241            self.instanceExtensions.append(self.ExtensionData(name=self.currentExtension,
242                                                              type=self.type,
243                                                              protect=self.featureExtraProtect,
244                                                              define=self.name_definition,
245                                                              num_commands=self.num_commands))
246
247        # Finish processing in superclass
248        OutputGenerator.endFeature(self)
249
250    #
251    # Retrieve the value of the len tag
252    def getLen(self, param):
253        result = None
254        len = param.attrib.get('len')
255        if len and len != 'null-terminated':
256            # For string arrays, 'len' can look like 'count,null-terminated',
257            # indicating that we have a null terminated array of strings.  We
258            # strip the null-terminated from the 'len' field and only return
259            # the parameter specifying the string count
260            if 'null-terminated' in len:
261                result = len.split(',')[0]
262            else:
263                result = len
264            result = str(result).replace('::', '->')
265        return result
266
267    #
268    # Determine if this API should be ignored or added to the instance or device dispatch table
269    def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
270        handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
271
272        return_type =  cmdinfo.elem.find('proto/type')
273        if (return_type != None and return_type.text == 'void'):
274           return_type = None
275
276        cmd_params = []
277
278        # Generate a list of commands for use in printing the necessary
279        # core instance terminator prototypes
280        params = cmdinfo.elem.findall('param')
281        lens = set()
282        for param in params:
283            len = self.getLen(param)
284            if len:
285                lens.add(len)
286        paramsInfo = []
287        for param in params:
288            paramInfo = self.getTypeNameTuple(param)
289            param_type = paramInfo[0]
290            param_name = paramInfo[1]
291            param_cdecl = self.makeCParamDecl(param, 0)
292            cmd_params.append(self.CommandParam(type=param_type, name=param_name,
293                                                cdecl=param_cdecl))
294
295        if handle != None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
296            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
297            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
298            if 'VK_VERSION_' in extension_name:
299                self.core_commands.append(
300                    self.CommandData(name=name, ext_name=extension_name,
301                                     ext_type='device',
302                                     protect=self.featureExtraProtect,
303                                     return_type = return_type,
304                                     handle_type = handle_type,
305                                     params = cmd_params,
306                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
307            else:
308                self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
309                self.ext_commands.append(
310                    self.CommandData(name=name, ext_name=extension_name,
311                                     ext_type=extension_type,
312                                     protect=self.featureExtraProtect,
313                                     return_type = return_type,
314                                     handle_type = handle_type,
315                                     params = cmd_params,
316                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
317        else:
318            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
319            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
320            if 'VK_VERSION_' in extension_name:
321                self.core_commands.append(
322                    self.CommandData(name=name, ext_name=extension_name,
323                                     ext_type='instance',
324                                     protect=self.featureExtraProtect,
325                                     return_type = return_type,
326                                     handle_type = handle_type,
327                                     params = cmd_params,
328                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
329
330            else:
331                self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
332                self.ext_commands.append(
333                    self.CommandData(name=name, ext_name=extension_name,
334                                     ext_type=extension_type,
335                                     protect=self.featureExtraProtect,
336                                     return_type = return_type,
337                                     handle_type = handle_type,
338                                     params = cmd_params,
339                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
340
341    #
342    # Retrieve the type and name for a parameter
343    def getTypeNameTuple(self, param):
344        type = ''
345        name = ''
346        for elem in param:
347            if elem.tag == 'type':
348                type = noneStr(elem.text)
349            elif elem.tag == 'name':
350                name = noneStr(elem.text)
351        return (type, name)
352
353    def OutputPrototypesInHeader(self):
354        protos = ''
355        protos += '// Structures defined externally, but used here\n'
356        protos += 'struct loader_instance;\n'
357        protos += 'struct loader_icd_term;\n'
358        protos += 'struct loader_dev_dispatch_table;\n'
359        protos += '\n'
360        protos += '// Device extension error function\n'
361        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev);\n'
362        protos += '\n'
363        protos += '// Extension interception for vkGetInstanceProcAddr function, so we can return\n'
364        protos += '// the appropriate information for any instance extensions we know about.\n'
365        protos += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);\n'
366        protos += '\n'
367        protos += '// Extension interception for vkCreateInstance function, so we can properly\n'
368        protos += '// detect and enable any instance extension information for extensions we know\n'
369        protos += '// about.\n'
370        protos += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);\n'
371        protos += '\n'
372        protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n'
373        protos += '// an appropriate terminator if this is one of those few device commands requiring\n'
374        protos += '// a terminator.\n'
375        protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(const char *pName);\n'
376        protos += '\n'
377        protos += '// Dispatch table properly filled in with appropriate terminators for the\n'
378        protos += '// supported extensions.\n'
379        protos += 'extern const VkLayerInstanceDispatchTable instance_disp;\n'
380        protos += '\n'
381        protos += '// Array of extension strings for instance extensions we support.\n'
382        protos += 'extern const char *const LOADER_INSTANCE_EXTENSIONS[];\n'
383        protos += '\n'
384        protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
385        protos += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa);\n'
386        protos += '\n'
387        protos += '// Init Device function pointer dispatch table with core commands\n'
388        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
389        protos += '                                                             VkDevice dev);\n'
390        protos += '\n'
391        protos += '// Init Device function pointer dispatch table with extension commands\n'
392        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
393        protos += '                                                                       PFN_vkGetDeviceProcAddr gpa, VkDevice dev);\n'
394        protos += '\n'
395        protos += '// Init Instance function pointer dispatch table with core commands\n'
396        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
397        protos += '                                                                    VkInstance inst);\n'
398        protos += '\n'
399        protos += '// Init Instance function pointer dispatch table with core commands\n'
400        protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
401        protos += '                                                                         VkInstance inst);\n'
402        protos += '\n'
403        protos += '// Device command lookup function\n'
404        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name);\n'
405        protos += '\n'
406        protos += '// Instance command lookup function\n'
407        protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
408        protos += '                                                                  bool *found_name);\n'
409        protos += '\n'
410        protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
411        protos += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa);\n'
412        protos += '\n'
413        return protos
414
415    def OutputUtilitiesInSource(self):
416        protos = ''
417        protos += '// Device extension error function\n'
418        protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev) {\n'
419        protos += '    struct loader_device *found_dev;\n'
420        protos += '    // The device going in is a trampoline device\n'
421        protos += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(dev, &found_dev, NULL);\n'
422        protos += '\n'
423        protos += '    if (icd_term)\n'
424        protos += '        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,\n'
425        protos += '                   "Bad destination in loader trampoline dispatch,"\n'
426        protos += '                   "Are layers and extensions that you are calling enabled?");\n'
427        protos += '    return VK_ERROR_EXTENSION_NOT_PRESENT;\n'
428        protos += '}\n\n'
429        return protos
430
431    #
432    # Create a layer instance dispatch table from the appropriate list and return it as a string
433    def OutputLayerInstanceDispatchTable(self):
434        commands = []
435        table = ''
436        cur_extension_name = ''
437
438        table += '// Instance function pointer dispatch table\n'
439        table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
440
441        # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
442        # ever show up in the XML or header, so we have to manually add it.
443        table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
444        table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
445
446        for x in range(0, 2):
447            if x == 0:
448                commands = self.core_commands
449            else:
450                commands = self.ext_commands
451
452            for cur_cmd in commands:
453                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
454                if is_inst_handle_type:
455
456                    if cur_cmd.ext_name != cur_extension_name:
457                        if 'VK_VERSION_' in cur_cmd.ext_name:
458                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
459                        else:
460                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
461                        cur_extension_name = cur_cmd.ext_name
462
463                    # Remove 'vk' from proto name
464                    base_name = cur_cmd.name[2:]
465
466                    if cur_cmd.protect is not None:
467                        table += '#ifdef %s\n' % cur_cmd.protect
468
469                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
470
471                    if cur_cmd.protect is not None:
472                        table += '#endif // %s\n' % cur_cmd.protect
473
474        table += '} VkLayerInstanceDispatchTable;\n\n'
475        return table
476
477    #
478    # Create a layer device dispatch table from the appropriate list and return it as a string
479    def OutputLayerDeviceDispatchTable(self):
480        commands = []
481        table = ''
482        cur_extension_name = ''
483
484        table += '// Device function pointer dispatch table\n'
485        table += 'typedef struct VkLayerDispatchTable_ {\n'
486
487        for x in range(0, 2):
488            if x == 0:
489                commands = self.core_commands
490            else:
491                commands = self.ext_commands
492
493            for cur_cmd in commands:
494                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
495                if not is_inst_handle_type:
496
497                    if cur_cmd.ext_name != cur_extension_name:
498                        if 'VK_VERSION_' in cur_cmd.ext_name:
499                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
500                        else:
501                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
502                        cur_extension_name = cur_cmd.ext_name
503
504                    # Remove 'vk' from proto name
505                    base_name = cur_cmd.name[2:]
506
507                    if cur_cmd.protect is not None:
508                        table += '#ifdef %s\n' % cur_cmd.protect
509
510                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
511
512                    if cur_cmd.protect is not None:
513                        table += '#endif // %s\n' % cur_cmd.protect
514
515        table += '} VkLayerDispatchTable;\n\n'
516        return table
517
518    #
519    # Create a dispatch table from the appropriate list and return it as a string
520    def OutputIcdDispatchTable(self):
521        commands = []
522        table = ''
523        cur_extension_name = ''
524
525        table += '// ICD function pointer dispatch table\n'
526        table += 'struct loader_icd_term_dispatch {\n'
527
528        for x in range(0, 2):
529            if x == 0:
530                commands = self.core_commands
531            else:
532                commands = self.ext_commands
533
534            for cur_cmd in commands:
535                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
536                if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and
537                    (cur_cmd.name != 'vkGetInstanceProcAddr' and cur_cmd.name != 'vkEnumerateDeviceLayerProperties')):
538
539                    if cur_cmd.ext_name != cur_extension_name:
540                        if 'VK_VERSION_' in cur_cmd.ext_name:
541                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
542                        else:
543                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
544                        cur_extension_name = cur_cmd.ext_name
545
546                    # Remove 'vk' from proto name
547                    base_name = cur_cmd.name[2:]
548
549                    if cur_cmd.protect is not None:
550                        table += '#ifdef %s\n' % cur_cmd.protect
551
552                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
553
554                    if cur_cmd.protect is not None:
555                        table += '#endif // %s\n' % cur_cmd.protect
556
557        table += '};\n\n'
558        return table
559
560    #
561    # Init a dispatch table from the appropriate list and return it as a string
562    def OutputIcdDispatchTableInit(self):
563        commands = []
564        cur_extension_name = ''
565
566        table = ''
567        table += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_icd_term *icd_term, VkInstance inst,\n'
568        table += '                                                   const PFN_vkGetInstanceProcAddr fp_gipa) {\n'
569        table += '\n'
570        table += '#define LOOKUP_GIPA(func, required)                                                        \\\n'
571        table += '    do {                                                                                   \\\n'
572        table += '        icd_term->dispatch.func = (PFN_vk##func)fp_gipa(inst, "vk" #func);                 \\\n'
573        table += '        if (!icd_term->dispatch.func && required) {                                        \\\n'
574        table += '            loader_log((struct loader_instance *)inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \\\n'
575        table += '                       loader_platform_get_proc_address_error("vk" #func));                \\\n'
576        table += '            return false;                                                                  \\\n'
577        table += '        }                                                                                  \\\n'
578        table += '    } while (0)\n'
579        table += '\n'
580
581        skip_gipa_commands = ['vkGetInstanceProcAddr',
582                              'vkEnumerateDeviceLayerProperties',
583                              'vkCreateInstance',
584                              'vkEnumerateInstanceExtensionProperties',
585                              'vkEnumerateInstanceLayerProperties',
586                             ]
587
588        for x in range(0, 2):
589            if x == 0:
590                commands = self.core_commands
591            else:
592                commands = self.ext_commands
593
594            for cur_cmd in commands:
595                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
596                if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and (cur_cmd.name not in skip_gipa_commands)):
597
598                    if cur_cmd.ext_name != cur_extension_name:
599                        if 'VK_VERSION_' in cur_cmd.ext_name:
600                            table += '\n    // ---- Core %s\n' % cur_cmd.ext_name[11:]
601                        else:
602                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
603                        cur_extension_name = cur_cmd.ext_name
604
605                    # Remove 'vk' from proto name
606                    base_name = cur_cmd.name[2:]
607
608                    if cur_cmd.protect is not None:
609                        table += '#ifdef %s\n' % cur_cmd.protect
610
611                    # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
612                    # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
613                    if x == 0:
614                        table += '    LOOKUP_GIPA(%s, true);\n' % (base_name)
615                    else:
616                        table += '    LOOKUP_GIPA(%s, false);\n' % (base_name)
617
618                    if cur_cmd.protect is not None:
619                        table += '#endif // %s\n' % cur_cmd.protect
620
621        table += '\n'
622        table += '#undef LOOKUP_GIPA\n'
623        table += '\n'
624        table += '    return true;\n'
625        table += '};\n\n'
626        return table
627
628    #
629    # Create the extension enable union
630    def OutputIcdExtensionEnableUnion(self):
631        extensions = self.instanceExtensions
632
633        union = ''
634        union += 'union loader_instance_extension_enables {\n'
635        union += '    struct {\n'
636        for ext in extensions:
637            if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
638                ext.type == 'device' or ext.num_commands == 0):
639                continue
640
641            union += '        uint8_t %s : 1;\n' % ext.name[3:].lower()
642
643        union += '    };\n'
644        union += '    uint64_t padding[4];\n'
645        union += '};\n\n'
646        return union
647
648    #
649    # Creates the prototypes for the loader's core instance command terminators
650    def OutputLoaderTerminators(self):
651        terminators = ''
652        terminators += '// Loader core instance terminators\n'
653
654        for cur_cmd in self.core_commands:
655            is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
656            if is_inst_handle_type:
657                mod_string = ''
658                new_terminator = cur_cmd.cdecl
659                mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_")
660
661                if cur_cmd.name in PRE_INSTANCE_FUNCTIONS:
662                    mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n    const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n')
663
664                if (cur_cmd.protect != None):
665                    terminators += '#ifdef %s\n' % cur_cmd.protect
666
667                terminators += mod_string
668                terminators += '\n'
669
670                if (cur_cmd.protect != None):
671                    terminators += '#endif // %s\n' % cur_cmd.protect
672
673        terminators += '\n'
674        return terminators
675
676    #
677    # Creates code to initialize the various dispatch tables
678    def OutputLoaderDispatchTables(self):
679        commands = []
680        tables = ''
681        gpa_param = ''
682        cur_type = ''
683        cur_extension_name = ''
684
685        for x in range(0, 4):
686            if x == 0:
687                cur_type = 'device'
688                gpa_param = 'dev'
689                commands = self.core_commands
690
691                tables += '// Init Device function pointer dispatch table with core commands\n'
692                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n'
693                tables += '                                                             VkDevice dev) {\n'
694                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
695                tables += '    for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch.dev_ext[i] = (PFN_vkDevExt)vkDevExtError;\n'
696
697            elif x == 1:
698                cur_type = 'device'
699                gpa_param = 'dev'
700                commands = self.ext_commands
701
702                tables += '// Init Device function pointer dispatch table with extension commands\n'
703                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n'
704                tables += '                                                                       PFN_vkGetDeviceProcAddr gpa, VkDevice dev) {\n'
705                tables += '    VkLayerDispatchTable *table = &dev_table->core_dispatch;\n'
706
707            elif x == 2:
708                cur_type = 'instance'
709                gpa_param = 'inst'
710                commands = self.core_commands
711
712                tables += '// Init Instance function pointer dispatch table with core commands\n'
713                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
714                tables += '                                                                    VkInstance inst) {\n'
715
716            else:
717                cur_type = 'instance'
718                gpa_param = 'inst'
719                commands = self.ext_commands
720
721                tables += '// Init Instance function pointer dispatch table with core commands\n'
722                tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n'
723                tables += '                                                                        VkInstance inst) {\n'
724
725            for cur_cmd in commands:
726                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
727                if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
728                    if cur_cmd.ext_name != cur_extension_name:
729                        if 'VK_VERSION_' in cur_cmd.ext_name:
730                            tables += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
731                        else:
732                            tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
733                        cur_extension_name = cur_cmd.ext_name
734
735                    # Remove 'vk' from proto name
736                    base_name = cur_cmd.name[2:]
737
738                    # Names to skip
739                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
740                        base_name == 'EnumerateInstanceExtensionProperties' or
741                        base_name == 'EnumerateInstanceLayerProperties'):
742                        continue
743
744                    if cur_cmd.protect is not None:
745                        tables += '#ifdef %s\n' % cur_cmd.protect
746
747                    # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
748                    # a layer overrides the function name for the loader.
749                    if (x <= 1 and base_name == 'GetDeviceProcAddr'):
750                        tables += '    table->GetDeviceProcAddr = gpa;\n'
751                    elif (x > 1 and base_name == 'GetInstanceProcAddr'):
752                        tables += '    table->GetInstanceProcAddr = gpa;\n'
753                    else:
754                        tables += '    table->%s = (PFN_%s)gpa(%s, "%s");\n' % (base_name, cur_cmd.name, gpa_param, cur_cmd.name)
755
756                    if cur_cmd.protect is not None:
757                        tables += '#endif // %s\n' % cur_cmd.protect
758
759            tables += '}\n\n'
760        return tables
761
762    #
763    # Create a lookup table function from the appropriate list of entrypoints and
764    # return it as a string
765    def OutputLoaderLookupFunc(self):
766        commands = []
767        tables = ''
768        cur_type = ''
769        cur_extension_name = ''
770
771        for x in range(0, 2):
772            if x == 0:
773                cur_type = 'device'
774
775                tables += '// Device command lookup function\n'
776                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name) {\n'
777                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') return NULL;\n'
778                tables += '\n'
779                tables += '    name += 2;\n'
780            else:
781                cur_type = 'instance'
782
783                tables += '// Instance command lookup function\n'
784                tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n'
785                tables += '                                                                 bool *found_name) {\n'
786                tables += '    if (!name || name[0] != \'v\' || name[1] != \'k\') {\n'
787                tables += '        *found_name = false;\n'
788                tables += '        return NULL;\n'
789                tables += '    }\n'
790                tables += '\n'
791                tables += '    *found_name = true;\n'
792                tables += '    name += 2;\n'
793
794            for y in range(0, 2):
795                if y == 0:
796                    commands = self.core_commands
797                else:
798                    commands = self.ext_commands
799
800                for cur_cmd in commands:
801                    is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
802                    if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)):
803
804                        if cur_cmd.ext_name != cur_extension_name:
805                            if 'VK_VERSION_' in cur_cmd.ext_name:
806                                tables += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
807                            else:
808                                tables += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
809                            cur_extension_name = cur_cmd.ext_name
810
811                        # Remove 'vk' from proto name
812                        base_name = cur_cmd.name[2:]
813
814                        if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
815                            base_name == 'EnumerateInstanceExtensionProperties' or
816                            base_name == 'EnumerateInstanceLayerProperties'):
817                            continue
818
819                        if cur_cmd.protect is not None:
820                            tables += '#ifdef %s\n' % cur_cmd.protect
821
822                        tables += '    if (!strcmp(name, "%s")) return (void *)table->%s;\n' % (base_name, base_name)
823
824                        if cur_cmd.protect is not None:
825                            tables += '#endif // %s\n' % cur_cmd.protect
826
827            tables += '\n'
828            if x == 1:
829                tables += '    *found_name = false;\n'
830            tables += '    return NULL;\n'
831            tables += '}\n\n'
832        return tables
833
834    #
835    # Create the appropriate trampoline (and possibly terminator) functinos
836    def CreateTrampTermFuncs(self):
837        entries = []
838        funcs = ''
839        cur_extension_name = ''
840
841        # Some extensions have to be manually added.  Skip those in the automatic
842        # generation.  They will be manually added later.
843        manual_ext_commands = ['vkEnumeratePhysicalDeviceGroupsKHX',
844                               'vkGetPhysicalDeviceExternalImageFormatPropertiesNV',
845                               'vkGetPhysicalDeviceFeatures2KHR',
846                               'vkGetPhysicalDeviceProperties2KHR',
847                               'vkGetPhysicalDeviceFormatProperties2KHR',
848                               'vkGetPhysicalDeviceImageFormatProperties2KHR',
849                               'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
850                               'vkGetPhysicalDeviceMemoryProperties2KHR',
851                               'vkGetPhysicalDeviceSparseImageFormatProperties2KHR',
852                               'vkGetPhysicalDeviceSurfaceCapabilities2KHR',
853                               'vkGetPhysicalDeviceSurfaceFormats2KHR',
854                               'vkGetPhysicalDeviceSurfaceCapabilities2EXT',
855                               'vkReleaseDisplayEXT',
856                               'vkAcquireXlibDisplayEXT',
857                               'vkGetRandROutputDisplayEXT',
858                               'vkGetPhysicalDeviceExternalBufferPropertiesKHR',
859                               'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR',
860                               'vkGetPhysicalDeviceExternalFencePropertiesKHR']
861
862        for ext_cmd in self.ext_commands:
863            if (ext_cmd.ext_name in WSI_EXT_NAMES or
864                ext_cmd.ext_name in AVOID_EXT_NAMES or
865                ext_cmd.name in manual_ext_commands):
866                continue
867
868            if ext_cmd.ext_name != cur_extension_name:
869                if 'VK_VERSION_' in ext_cmd.ext_name:
870                    funcs += '\n// ---- Core %s trampoline/terminators\n\n' % ext_cmd.ext_name[11:]
871                else:
872                    funcs += '\n// ---- %s extension trampoline/terminators\n\n' % ext_cmd.ext_name
873                cur_extension_name = ext_cmd.ext_name
874
875            if ext_cmd.protect is not None:
876                funcs += '#ifdef %s\n' % ext_cmd.protect
877
878            func_header = ext_cmd.cdecl.replace(";", " {\n")
879            tramp_header = func_header.replace("VKAPI_CALL vk", "VKAPI_CALL ")
880            return_prefix = '    '
881            base_name = ext_cmd.name[2:]
882            has_surface = 0
883            update_structure_surface = 0
884            update_structure_string = ''
885            requires_terminator = 0
886            surface_var_name = ''
887            phys_dev_var_name = ''
888            has_return_type = False
889            always_use_param_name = True
890            surface_type_to_replace = ''
891            surface_name_replacement = ''
892            physdev_type_to_replace = ''
893            physdev_name_replacement = ''
894
895            for param in ext_cmd.params:
896                if param.type == 'VkSurfaceKHR':
897                    has_surface = 1
898                    surface_var_name = param.name
899                    requires_terminator = 1
900                    always_use_param_name = False
901                    surface_type_to_replace = 'VkSurfaceKHR'
902                    surface_name_replacement = 'icd_surface->real_icd_surfaces[icd_index]'
903                if param.type == 'VkPhysicalDeviceSurfaceInfo2KHR':
904                    has_surface = 1
905                    surface_var_name = param.name + '->surface'
906                    requires_terminator = 1
907                    update_structure_surface = 1
908                    update_structure_string = '        VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;\n'
909                    update_structure_string += '        info_copy.surface = icd_surface->real_icd_surfaces[icd_index];\n'
910                    always_use_param_name = False
911                    surface_type_to_replace = 'VkPhysicalDeviceSurfaceInfo2KHR'
912                    surface_name_replacement = '&info_copy'
913                if param.type == 'VkPhysicalDevice':
914                    requires_terminator = 1
915                    phys_dev_var_name = param.name
916                    always_use_param_name = False
917                    physdev_type_to_replace = 'VkPhysicalDevice'
918                    physdev_name_replacement = 'phys_dev_term->phys_dev'
919
920            if (ext_cmd.return_type != None):
921                return_prefix += 'return '
922                has_return_type = True
923
924            if (ext_cmd.ext_type == 'instance' or ext_cmd.handle_type == 'VkPhysicalDevice' or
925                'DebugMarkerSetObject' in ext_cmd.name or ext_cmd.name in DEVICE_CMDS_NEED_TERM):
926                requires_terminator = 1
927
928            if requires_terminator == 1:
929                term_header = tramp_header.replace("VKAPI_CALL ", "VKAPI_CALL terminator_")
930
931                funcs += tramp_header
932
933                if ext_cmd.handle_type == 'VkPhysicalDevice':
934                    funcs += '    const VkLayerInstanceDispatchTable *disp;\n'
935                    funcs += '    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(%s);\n' % (phys_dev_var_name)
936                    funcs += '    disp = loader_get_instance_layer_dispatch(%s);\n' % (phys_dev_var_name)
937                elif ext_cmd.handle_type == 'VkInstance':
938                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
939                else:
940                    funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
941                    funcs += ext_cmd.params[0].name
942                    funcs += ');\n'
943
944                if 'DebugMarkerSetObjectName' in ext_cmd.name:
945                    funcs += '    VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
946                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
947                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
948                    funcs += '    if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
949                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->object;\n'
950                    funcs += '        local_name_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
951                    funcs += '    }\n'
952                elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
953                    funcs += '    VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
954                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
955                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
956                    funcs += '    if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
957                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n'
958                    funcs += '        local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
959                    funcs += '    }\n'
960
961                funcs += return_prefix
962                funcs += 'disp->'
963                funcs += base_name
964                funcs += '('
965                count = 0
966                for param in ext_cmd.params:
967                    if count != 0:
968                        funcs += ', '
969
970                    if param.type == 'VkPhysicalDevice':
971                        funcs += 'unwrapped_phys_dev'
972                    elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pNameInfo':
973                            funcs += '&local_name_info'
974                    elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pTagInfo':
975                            funcs += '&local_tag_info'
976                    else:
977                        funcs += param.name
978
979                    count += 1
980                funcs += ');\n'
981                funcs += '}\n\n'
982
983                funcs += term_header
984                if ext_cmd.handle_type == 'VkPhysicalDevice':
985                    funcs += '    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)%s;\n' % (phys_dev_var_name)
986                    funcs += '    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;\n'
987                    funcs += '    if (NULL == icd_term->dispatch.'
988                    funcs += base_name
989                    funcs += ') {\n'
990                    funcs += '        loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,\n'
991                    funcs += '                   "ICD associated with VkPhysicalDevice does not support '
992                    funcs += base_name
993                    funcs += '");\n'
994                    funcs += '    }\n'
995
996                    if has_surface == 1:
997                        funcs += '    VkIcdSurface *icd_surface = (VkIcdSurface *)(%s);\n' % (surface_var_name)
998                        funcs += '    uint8_t icd_index = phys_dev_term->icd_index;\n'
999                        funcs += '    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)icd_surface->real_icd_surfaces[icd_index]) {\n'
1000
1001                        # If there's a structure with a surface, we need to update its internals with the correct surface for the ICD
1002                        if update_structure_surface == 1:
1003                            funcs += update_structure_string
1004
1005                        funcs += '    ' + return_prefix + 'icd_term->dispatch.'
1006                        funcs += base_name
1007                        funcs += '('
1008                        count = 0
1009                        for param in ext_cmd.params:
1010                            if count != 0:
1011                                funcs += ', '
1012
1013                            if not always_use_param_name:
1014                                if surface_type_to_replace and surface_type_to_replace == param.type:
1015                                    funcs += surface_name_replacement
1016                                elif physdev_type_to_replace and physdev_type_to_replace == param.type:
1017                                    funcs += physdev_name_replacement
1018                                else:
1019                                    funcs += param.name
1020                            else:
1021                                funcs += param.name
1022
1023                            count += 1
1024                        funcs += ');\n'
1025                        if not has_return_type:
1026                            funcs += '        return;\n'
1027                        funcs += '    }\n'
1028
1029                    funcs += return_prefix
1030                    funcs += 'icd_term->dispatch.'
1031                    funcs += base_name
1032                    funcs += '('
1033                    count = 0
1034                    for param in ext_cmd.params:
1035                        if count != 0:
1036                            funcs += ', '
1037
1038                        if param.type == 'VkPhysicalDevice':
1039                            funcs += 'phys_dev_term->phys_dev'
1040                        else:
1041                            funcs += param.name
1042
1043                        count += 1
1044                    funcs += ');\n'
1045
1046                elif has_surface == 1 and ext_cmd.ext_type == 'device':
1047                    funcs += '    uint32_t icd_index = 0;\n'
1048                    funcs += '    struct loader_device *dev;\n'
1049                    funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);\n'
1050                    funcs += '    if (NULL != icd_term && NULL != icd_term->dispatch.%s) {\n' % base_name
1051                    funcs += '        VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s;\n' % (surface_var_name)
1052                    funcs += '        if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {\n'
1053                    funcs += '        %sicd_term->dispatch.%s(' % (return_prefix, base_name)
1054                    count = 0
1055                    for param in ext_cmd.params:
1056                        if count != 0:
1057                            funcs += ', '
1058
1059                        if param.type == 'VkSurfaceKHR':
1060                            funcs += 'icd_surface->real_icd_surfaces[icd_index]'
1061                        else:
1062                            funcs += param.name
1063
1064                        count += 1
1065                    funcs += ');\n'
1066                    if not has_return_type:
1067                        funcs += '                return;\n'
1068                    funcs += '        }\n'
1069                    funcs += '    %sicd_term->dispatch.%s(' % (return_prefix, base_name)
1070                    count = 0
1071                    for param in ext_cmd.params:
1072                        if count != 0:
1073                            funcs += ', '
1074                        funcs += param.name
1075                        count += 1
1076                    funcs += ');\n'
1077                    funcs += '    }\n'
1078                    if has_return_type:
1079                        funcs += '    return VK_SUCCESS;\n'
1080
1081                elif ext_cmd.handle_type == 'VkInstance':
1082                    funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
1083                elif 'DebugMarkerSetObject' in ext_cmd.name:
1084                    funcs += '    uint32_t icd_index = 0;\n'
1085                    funcs += '    struct loader_device *dev;\n'
1086                    funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(%s, &dev, &icd_index);\n' % (ext_cmd.params[0].name)
1087                    funcs += '    if (NULL != icd_term && NULL != icd_term->dispatch.'
1088                    funcs += base_name
1089                    funcs += ') {\n'
1090                    if 'DebugMarkerSetObjectName' in ext_cmd.name:
1091                        funcs += '        VkDebugMarkerObjectNameInfoEXT local_name_info;\n'
1092                        funcs += '        memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n'
1093                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1094                        funcs += '        if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
1095                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;\n'
1096                        funcs += '            local_name_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
1097                        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'
1098                        funcs += '        } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
1099                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
1100                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;\n'
1101                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
1102                        funcs += '                    local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
1103                        funcs += '                }\n'
1104                    elif 'DebugMarkerSetObjectTag' in ext_cmd.name:
1105                        funcs += '        VkDebugMarkerObjectTagInfoEXT local_tag_info;\n'
1106                        funcs += '        memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n'
1107                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
1108                        funcs += '        if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n'
1109                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;\n'
1110                        funcs += '            local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
1111                        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'
1112                        funcs += '        } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
1113                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
1114                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;\n'
1115                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
1116                        funcs += '                    local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
1117                        funcs += '                }\n'
1118                    funcs += '            }\n'
1119                    funcs += '        }\n'
1120                    funcs += '        return icd_term->dispatch.'
1121                    funcs += base_name
1122                    funcs += '('
1123                    count = 0
1124                    for param in ext_cmd.params:
1125                        if count != 0:
1126                            funcs += ', '
1127
1128                        if param.type == 'VkPhysicalDevice':
1129                            funcs += 'phys_dev_term->phys_dev'
1130                        elif param.type == 'VkSurfaceKHR':
1131                            funcs += 'icd_surface->real_icd_surfaces[icd_index]'
1132                        elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pNameInfo':
1133                            funcs += '&local_name_info'
1134                        elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pTagInfo':
1135                            funcs += '&local_tag_info'
1136                        else:
1137                            funcs += param.name
1138                        count += 1
1139
1140                    funcs += ');\n'
1141                    funcs += '    } else {\n'
1142                    funcs += '        return VK_SUCCESS;\n'
1143                    funcs += '    }\n'
1144
1145                else:
1146                    funcs += '#error("Unknown error path!");\n'
1147
1148                funcs += '}\n\n'
1149            else:
1150                funcs += tramp_header
1151
1152                funcs += '    const VkLayerDispatchTable *disp = loader_get_dispatch('
1153                funcs += ext_cmd.params[0].name
1154                funcs += ');\n'
1155
1156                funcs += return_prefix
1157                funcs += 'disp->'
1158                funcs += base_name
1159                funcs += '('
1160                count = 0
1161                for param in ext_cmd.params:
1162                    if count != 0:
1163                        funcs += ', '
1164                    funcs += param.name
1165                    count += 1
1166                funcs += ');\n'
1167                funcs += '}\n\n'
1168
1169            if ext_cmd.protect is not None:
1170                funcs += '#endif // %s\n' % ext_cmd.protect
1171
1172        return funcs
1173
1174
1175    #
1176    # Create a function for the extension GPA call
1177    def InstExtensionGPA(self):
1178        entries = []
1179        gpa_func = ''
1180        cur_extension_name = ''
1181
1182        gpa_func += '// GPA helpers for extensions\n'
1183        gpa_func += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {\n'
1184        gpa_func += '    *addr = NULL;\n\n'
1185
1186        for cur_cmd in self.ext_commands:
1187            if ('VK_VERSION_' in cur_cmd.ext_name or
1188                cur_cmd.ext_name in WSI_EXT_NAMES or
1189                cur_cmd.ext_name in AVOID_EXT_NAMES):
1190                continue
1191
1192            if cur_cmd.ext_name != cur_extension_name:
1193                gpa_func += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
1194                cur_extension_name = cur_cmd.ext_name
1195
1196            if cur_cmd.protect is not None:
1197                gpa_func += '#ifdef %s\n' % cur_cmd.protect
1198
1199            base_name = cur_cmd.name[2:]
1200
1201            if (cur_cmd.ext_type == 'instance'):
1202                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
1203                gpa_func += '        *addr = (ptr_instance->enabled_known_extensions.'
1204                gpa_func += cur_cmd.ext_name[3:].lower()
1205                gpa_func += ' == 1)\n'
1206                gpa_func += '                     ? (void *)%s\n' % (base_name)
1207                gpa_func += '                     : NULL;\n'
1208                gpa_func += '        return true;\n'
1209                gpa_func += '    }\n'
1210            else:
1211                gpa_func += '    if (!strcmp("%s", name)) {\n' % (cur_cmd.name)
1212                gpa_func += '        *addr = (void *)%s;\n' % (base_name)
1213                gpa_func += '        return true;\n'
1214                gpa_func += '    }\n'
1215
1216            if cur_cmd.protect is not None:
1217                gpa_func += '#endif // %s\n' % cur_cmd.protect
1218
1219        gpa_func += '    return false;\n'
1220        gpa_func += '}\n\n'
1221
1222        return gpa_func
1223
1224    #
1225    # Create the extension name init function
1226    def InstantExtensionCreate(self):
1227        entries = []
1228        entries = self.instanceExtensions
1229        count = 0
1230        cur_extension_name = ''
1231
1232        create_func = ''
1233        create_func += '// A function that can be used to query enabled extensions during a vkCreateInstance call\n'
1234        create_func += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {\n'
1235        create_func += '    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n'
1236        for ext in entries:
1237            if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
1238                ext.name in AVOID_EXT_NAMES or ext.type == 'device' or
1239                ext.num_commands == 0):
1240                continue
1241
1242            if ext.name != cur_extension_name:
1243                create_func += '\n    // ---- %s extension commands\n' % ext.name
1244                cur_extension_name = ext.name
1245
1246            if ext.protect is not None:
1247                create_func += '#ifdef %s\n' % ext.protect
1248            if count == 0:
1249                create_func += '        if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
1250            else:
1251                create_func += '        } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], '
1252
1253            create_func += ext.define + ')) {\n'
1254            create_func += '            ptr_instance->enabled_known_extensions.'
1255            create_func += ext.name[3:].lower()
1256            create_func += ' = 1;\n'
1257
1258            if ext.protect is not None:
1259                create_func += '#endif // %s\n' % ext.protect
1260            count += 1
1261
1262        create_func += '        }\n'
1263        create_func += '    }\n'
1264        create_func += '}\n\n'
1265        return create_func
1266
1267    #
1268    # Create code to initialize a dispatch table from the appropriate list of
1269    # extension entrypoints and return it as a string
1270    def DeviceExtensionGetTerminator(self):
1271        term_func = ''
1272        cur_extension_name = ''
1273
1274        term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n'
1275        term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object.  But there may be other items\n'
1276        term_func += '// in the future.\n'
1277        term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(const char *pName) {\n'
1278        term_func += '    PFN_vkVoidFunction addr = NULL;\n'
1279
1280        count = 0
1281        for ext_cmd in self.ext_commands:
1282            if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
1283                if ext_cmd.ext_name != cur_extension_name:
1284                    if 'VK_VERSION_' in ext_cmd.ext_name:
1285                        term_func += '\n    // ---- Core %s commands\n' % ext_cmd.ext_name[11:]
1286                    else:
1287                        term_func += '\n    // ---- %s extension commands\n' % ext_cmd.ext_name
1288                    cur_extension_name = ext_cmd.ext_name
1289
1290                if ext_cmd.protect is not None:
1291                    term_func += '#ifdef %s\n' % ext_cmd.protect
1292
1293                if count == 0:
1294                    term_func += '    if'
1295                else:
1296                    term_func += '    } else if'
1297                term_func += '(!strcmp(pName, "%s")) {\n' % (ext_cmd.name)
1298                term_func += '        addr = (PFN_vkVoidFunction)terminator_%s;\n' % (ext_cmd.name[2:])
1299
1300                if ext_cmd.protect is not None:
1301                    term_func += '#endif // %s\n' % ext_cmd.protect
1302
1303                count += 1
1304
1305        if count > 0:
1306            term_func += '    }\n'
1307
1308        term_func += '    return addr;\n'
1309        term_func += '}\n\n'
1310
1311        return term_func
1312
1313    #
1314    # Create code to initialize a dispatch table from the appropriate list of
1315    # core and extension entrypoints and return it as a string
1316    def InitInstLoaderExtensionDispatchTable(self):
1317        commands = []
1318        table = ''
1319        cur_extension_name = ''
1320
1321        table += '// This table contains the loader\'s instance dispatch table, which contains\n'
1322        table += '// default functions if no instance layers are activated.  This contains\n'
1323        table += '// pointers to "terminator functions".\n'
1324        table += 'const VkLayerInstanceDispatchTable instance_disp = {\n'
1325
1326        for x in range(0, 2):
1327            if x == 0:
1328                commands = self.core_commands
1329            else:
1330                commands = self.ext_commands
1331
1332            for cur_cmd in commands:
1333                if cur_cmd.ext_type == 'instance' or (cur_cmd.ext_type == 'device' and cur_cmd.handle_type == 'VkPhysicalDevice'):
1334                    if cur_cmd.ext_name != cur_extension_name:
1335                        if 'VK_VERSION_' in cur_cmd.ext_name:
1336                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
1337                        else:
1338                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
1339                        cur_extension_name = cur_cmd.ext_name
1340
1341                    # Remove 'vk' from proto name
1342                    base_name = cur_cmd.name[2:]
1343
1344                    if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or
1345                        base_name == 'EnumerateInstanceExtensionProperties' or
1346                        base_name == 'EnumerateInstanceLayerProperties'):
1347                        continue
1348
1349                    if cur_cmd.protect is not None:
1350                        table += '#ifdef %s\n' % cur_cmd.protect
1351
1352                    if base_name == 'GetInstanceProcAddr':
1353                        table += '    .%s = %s,\n' % (base_name, cur_cmd.name)
1354                    else:
1355                        table += '    .%s = terminator_%s,\n' % (base_name, base_name)
1356
1357                    if cur_cmd.protect is not None:
1358                        table += '#endif // %s\n' % cur_cmd.protect
1359        table += '};\n\n'
1360
1361        return table
1362
1363    #
1364    # Create the extension name whitelist array
1365    def OutputInstantExtensionWhitelistArray(self):
1366        extensions = self.instanceExtensions
1367
1368        table = ''
1369        table += '// A null-terminated list of all of the instance extensions supported by the loader.\n'
1370        table += '// If an instance extension name is not in this list, but it is exported by one or more of the\n'
1371        table += '// ICDs detected by the loader, then the extension name not in the list will be filtered out\n'
1372        table += '// before passing the list of extensions to the application.\n'
1373        table += 'const char *const LOADER_INSTANCE_EXTENSIONS[] = {\n'
1374        for ext in extensions:
1375            if ext.type == 'device' or 'VK_VERSION_' in ext.name:
1376                continue
1377
1378            if ext.protect is not None:
1379                table += '#ifdef %s\n' % ext.protect
1380            table += '                                                  '
1381            table += ext.define + ',\n'
1382
1383            if ext.protect is not None:
1384                table += '#endif // %s\n' % ext.protect
1385        table += '                                                  NULL };\n'
1386        return table
1387
1388