• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2019 The Khronos Group Inc.
4# Copyright (c) 2015-2019 Valve Corporation
5# Copyright (c) 2015-2019 LunarG, Inc.
6# Copyright (c) 2015-2019 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# Author: Mark Lobodzinski <mark@lunarg.com>
22
23import os,re,sys
24import xml.etree.ElementTree as etree
25from generator import *
26from collections import namedtuple
27from common_codegen import *
28
29ADD_INST_CMDS = ['vkCreateInstance',
30                 'vkEnumerateInstanceExtensionProperties',
31                 'vkEnumerateInstanceLayerProperties',
32                 'vkEnumerateInstanceVersion']
33
34#
35# LayerDispatchTableGeneratorOptions - subclass of GeneratorOptions.
36class LayerDispatchTableGeneratorOptions(GeneratorOptions):
37    def __init__(self,
38                 conventions = None,
39                 filename = None,
40                 directory = '.',
41                 apiname = None,
42                 profile = None,
43                 versions = '.*',
44                 emitversions = '.*',
45                 defaultExtensions = None,
46                 addExtensions = None,
47                 removeExtensions = None,
48                 emitExtensions = None,
49                 sortProcedure = regSortFeatures,
50                 prefixText = "",
51                 genFuncPointers = True,
52                 protectFile = True,
53                 protectFeature = True,
54                 apicall = '',
55                 apientry = '',
56                 apientryp = '',
57                 indentFuncProto = True,
58                 indentFuncPointer = False,
59                 alignFuncParam = 0,
60                 expandEnumerants = True):
61        GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile,
62                                  versions, emitversions, defaultExtensions,
63                                  addExtensions, removeExtensions, emitExtensions, sortProcedure)
64        self.prefixText      = prefixText
65        self.prefixText      = None
66        self.apicall         = apicall
67        self.apientry        = apientry
68        self.apientryp       = apientryp
69        self.alignFuncParam  = alignFuncParam
70        self.expandEnumerants = expandEnumerants
71
72#
73# LayerDispatchTableOutputGenerator - subclass of OutputGenerator.
74# Generates dispatch table helper header files for LVL
75class LayerDispatchTableOutputGenerator(OutputGenerator):
76    """Generate dispatch tables header based on XML element attributes"""
77    def __init__(self,
78                 errFile = sys.stderr,
79                 warnFile = sys.stderr,
80                 diagFile = sys.stdout):
81        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
82
83        # Internal state - accumulators for different inner block text
84        self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
85        self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
86        self.core_commands = []               # List of CommandData records for core Vulkan commands
87        self.ext_commands = []                # List of CommandData records for extension Vulkan commands
88        self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
89        self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
90
91    #
92    # Called once at the beginning of each run
93    def beginFile(self, genOpts):
94        OutputGenerator.beginFile(self, genOpts)
95
96        # Initialize members that require the tree
97        self.handle_types = GetHandleTypes(self.registry.tree)
98
99        # User-supplied prefix text, if any (list of strings)
100        if (genOpts.prefixText):
101            for s in genOpts.prefixText:
102                write(s, file=self.outFile)
103
104        # File Comment
105        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
106        file_comment += '// See layer_dispatch_table_generator.py for modifications\n'
107        write(file_comment, file=self.outFile)
108
109        # Copyright Notice
110        copyright =  '/*\n'
111        copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n'
112        copyright += ' * Copyright (c) 2015-2019 Valve Corporation\n'
113        copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n'
114        copyright += ' *\n'
115        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
116        copyright += ' * you may not use this file except in compliance with the License.\n'
117        copyright += ' * You may obtain a copy of the License at\n'
118        copyright += ' *\n'
119        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
120        copyright += ' *\n'
121        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
122        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
123        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
124        copyright += ' * See the License for the specific language governing permissions and\n'
125        copyright += ' * limitations under the License.\n'
126        copyright += ' *\n'
127        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
128        copyright += ' * Author: Mark Young <marky@lunarg.com>\n'
129        copyright += ' */\n'
130
131        preamble = ''
132        if self.genOpts.filename == 'vk_layer_dispatch_table.h':
133            preamble += '#pragma once\n'
134            preamble += '\n'
135            preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
136
137        write(copyright, file=self.outFile)
138        write(preamble, file=self.outFile)
139
140    #
141    # Write generate and write dispatch tables to output file
142    def endFile(self):
143        file_data = ''
144        if self.genOpts.filename == 'vk_layer_dispatch_table.h':
145            file_data += self.OutputLayerInstanceDispatchTable()
146            file_data += self.OutputLayerDeviceDispatchTable()
147
148        write(file_data, file=self.outFile);
149
150        # Finish processing in superclass
151        OutputGenerator.endFile(self)
152
153    def beginFeature(self, interface, emit):
154        # Start processing in superclass
155        OutputGenerator.beginFeature(self, interface, emit)
156        self.featureExtraProtect = GetFeatureProtect(interface)
157
158        enums = interface[0].findall('enum')
159        self.currentExtension = ''
160
161        self.type = interface.get('type')
162        self.num_commands = 0
163        name = interface.get('name')
164        self.currentExtension = name
165
166    #
167    # Process commands, adding to appropriate dispatch tables
168    def genCmd(self, cmdinfo, name, alias):
169        OutputGenerator.genCmd(self, cmdinfo, name, alias)
170
171        # Get first param type
172        params = cmdinfo.elem.findall('param')
173        info = self.getTypeNameTuple(params[0])
174
175        self.num_commands += 1
176
177        if 'android' not in name:
178            self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
179
180    def endFeature(self):
181        # Finish processing in superclass
182        OutputGenerator.endFeature(self)
183
184    #
185    # Retrieve the value of the len tag
186    def getLen(self, param):
187        result = None
188        len = param.attrib.get('len')
189        if len and len != 'null-terminated':
190            # For string arrays, 'len' can look like 'count,null-terminated',
191            # indicating that we have a null terminated array of strings.  We
192            # strip the null-terminated from the 'len' field and only return
193            # the parameter specifying the string count
194            if 'null-terminated' in len:
195                result = len.split(',')[0]
196            else:
197                result = len
198            result = str(result).replace('::', '->')
199        return result
200
201    #
202    # Determine if this API should be ignored or added to the instance or device dispatch table
203    def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
204        return_type =  cmdinfo.elem.find('proto/type')
205        if (return_type is not None and return_type.text == 'void'):
206           return_type = None
207
208        cmd_params = []
209
210        # Generate a list of commands for use in printing the necessary
211        # core instance terminator prototypes
212        params = cmdinfo.elem.findall('param')
213        lens = set()
214        for param in params:
215            len = self.getLen(param)
216            if len:
217                lens.add(len)
218        paramsInfo = []
219        for param in params:
220            paramInfo = self.getTypeNameTuple(param)
221            param_type = paramInfo[0]
222            param_name = paramInfo[1]
223            param_cdecl = self.makeCParamDecl(param, 0)
224            cmd_params.append(self.CommandParam(type=param_type, name=param_name,
225                                                cdecl=param_cdecl))
226
227        if handle_type in self.handle_types and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
228            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
229            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
230            if 'VK_VERSION_' in extension_name:
231                self.core_commands.append(
232                    self.CommandData(name=name, ext_name=extension_name,
233                                     ext_type='device',
234                                     protect=self.featureExtraProtect,
235                                     return_type = return_type,
236                                     handle_type = handle_type,
237                                     params = cmd_params,
238                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
239            else:
240                self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
241                self.ext_commands.append(
242                    self.CommandData(name=name, ext_name=extension_name,
243                                     ext_type=extension_type,
244                                     protect=self.featureExtraProtect,
245                                     return_type = return_type,
246                                     handle_type = handle_type,
247                                     params = cmd_params,
248                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
249        else:
250            # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
251            # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
252            if 'VK_VERSION_' in extension_name:
253                self.core_commands.append(
254                    self.CommandData(name=name, ext_name=extension_name,
255                                     ext_type='instance',
256                                     protect=self.featureExtraProtect,
257                                     return_type = return_type,
258                                     handle_type = handle_type,
259                                     params = cmd_params,
260                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
261
262            else:
263                self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
264                self.ext_commands.append(
265                    self.CommandData(name=name, ext_name=extension_name,
266                                     ext_type=extension_type,
267                                     protect=self.featureExtraProtect,
268                                     return_type = return_type,
269                                     handle_type = handle_type,
270                                     params = cmd_params,
271                                     cdecl=self.makeCDecls(cmdinfo.elem)[0]))
272
273    #
274    # Retrieve the type and name for a parameter
275    def getTypeNameTuple(self, param):
276        type = ''
277        name = ''
278        for elem in param:
279            if elem.tag == 'type':
280                type = noneStr(elem.text)
281            elif elem.tag == 'name':
282                name = noneStr(elem.text)
283        return (type, name)
284
285    #
286    # Create a layer instance dispatch table from the appropriate list and return it as a string
287    def OutputLayerInstanceDispatchTable(self):
288        commands = []
289        table = ''
290        cur_extension_name = ''
291
292        table += '// Instance function pointer dispatch table\n'
293        table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
294
295        # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
296        # ever show up in the XML or header, so we have to manually add it.
297        table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
298        table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
299
300        for x in range(0, 2):
301            if x == 0:
302                commands = self.core_commands
303            else:
304                commands = self.ext_commands
305
306            for cur_cmd in commands:
307                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
308                if is_inst_handle_type:
309
310                    if cur_cmd.ext_name != cur_extension_name:
311                        if 'VK_VERSION_' in cur_cmd.ext_name:
312                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
313                        else:
314                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
315                        cur_extension_name = cur_cmd.ext_name
316
317                    # Remove 'vk' from proto name
318                    base_name = cur_cmd.name[2:]
319
320                    if cur_cmd.protect is not None:
321                        table += '#ifdef %s\n' % cur_cmd.protect
322
323                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
324
325                    if cur_cmd.protect is not None:
326                        table += '#endif // %s\n' % cur_cmd.protect
327
328        table += '} VkLayerInstanceDispatchTable;\n\n'
329        return table
330
331    #
332    # Create a layer device dispatch table from the appropriate list and return it as a string
333    def OutputLayerDeviceDispatchTable(self):
334        commands = []
335        table = ''
336        cur_extension_name = ''
337
338        table += '// Device function pointer dispatch table\n'
339        table += 'typedef struct VkLayerDispatchTable_ {\n'
340
341        for x in range(0, 2):
342            if x == 0:
343                commands = self.core_commands
344            else:
345                commands = self.ext_commands
346
347            for cur_cmd in commands:
348                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
349                if not is_inst_handle_type:
350
351                    if cur_cmd.ext_name != cur_extension_name:
352                        if 'VK_VERSION_' in cur_cmd.ext_name:
353                            table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
354                        else:
355                            table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
356                        cur_extension_name = cur_cmd.ext_name
357
358                    # Remove 'vk' from proto name
359                    base_name = cur_cmd.name[2:]
360
361                    if cur_cmd.protect is not None:
362                        table += '#ifdef %s\n' % cur_cmd.protect
363
364                    table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
365
366                    if cur_cmd.protect is not None:
367                        table += '#endif // %s\n' % cur_cmd.protect
368
369        table += '} VkLayerDispatchTable;\n\n'
370        return table
371