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