• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2021 The Khronos Group Inc.
4# Copyright (c) 2015-2021 Valve Corporation
5# Copyright (c) 2015-2021 LunarG, Inc.
6# Copyright (c) 2015-2021 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 Lobodzinski <mark@lunarg.com>
21
22import os,re,sys
23import xml.etree.ElementTree as etree
24from generator import *
25from collections import namedtuple
26from common_codegen import *
27
28return_type_table = {"VkResult": "VK_SUCCESS",
29                     "uint32_t": "0",
30                     "uint64_t": "0L",
31                     "VkDeviceAddress": "0L",
32                     "VkDeviceSize": "0L"}
33
34#
35# DispatchTableHelperOutputGeneratorOptions - subclass of GeneratorOptions.
36class DispatchTableHelperOutputGeneratorOptions(GeneratorOptions):
37    def __init__(self,
38                 conventions = None,
39                 filename = None,
40                 directory = '.',
41                 genpath = None,
42                 apiname = None,
43                 profile = None,
44                 versions = '.*',
45                 emitversions = '.*',
46                 defaultExtensions = None,
47                 addExtensions = None,
48                 removeExtensions = None,
49                 emitExtensions = None,
50                 sortProcedure = regSortFeatures,
51                 prefixText = "",
52                 genFuncPointers = True,
53                 apicall = '',
54                 apientry = '',
55                 apientryp = '',
56                 alignFuncParam = 0,
57                 expandEnumerants = True):
58        GeneratorOptions.__init__(self,
59                conventions = conventions,
60                filename = filename,
61                directory = directory,
62                genpath = genpath,
63                apiname = apiname,
64                profile = profile,
65                versions = versions,
66                emitversions = emitversions,
67                defaultExtensions = defaultExtensions,
68                addExtensions = addExtensions,
69                removeExtensions = removeExtensions,
70                emitExtensions = emitExtensions,
71                sortProcedure = sortProcedure)
72        self.prefixText      = prefixText
73        self.genFuncPointers = genFuncPointers
74        self.prefixText      = None
75        self.apicall         = apicall
76        self.apientry        = apientry
77        self.apientryp       = apientryp
78        self.alignFuncParam  = alignFuncParam
79#
80# DispatchTableHelperOutputGenerator - subclass of OutputGenerator.
81# Generates dispatch table helper header files for LVL
82class DispatchTableHelperOutputGenerator(OutputGenerator):
83    """Generate dispatch table helper header based on XML element attributes"""
84    def __init__(self,
85                 errFile = sys.stderr,
86                 warnFile = sys.stderr,
87                 diagFile = sys.stdout):
88        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
89        # Internal state - accumulators for different inner block text
90        self.instance_dispatch_list = []      # List of entries for instance dispatch list
91        self.device_dispatch_list = []        # List of entries for device dispatch list
92        self.dev_ext_stub_list = []           # List of stub functions for device extension functions
93        self.device_extension_list = []       # List of device extension functions
94        self.extension_type = ''
95    #
96    # Called once at the beginning of each run
97    def beginFile(self, genOpts):
98        OutputGenerator.beginFile(self, genOpts)
99        write("#pragma once", file=self.outFile)
100        # User-supplied prefix text, if any (list of strings)
101        if (genOpts.prefixText):
102            for s in genOpts.prefixText:
103                write(s, file=self.outFile)
104        # File Comment
105        file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
106        file_comment += '// See dispatch_helper_generator.py for modifications\n'
107        write(file_comment, file=self.outFile)
108        # Copyright Notice
109        copyright =  '/*\n'
110        copyright += ' * Copyright (c) 2015-2021 The Khronos Group Inc.\n'
111        copyright += ' * Copyright (c) 2015-2021 Valve Corporation\n'
112        copyright += ' * Copyright (c) 2015-2021 LunarG, Inc.\n'
113        copyright += ' *\n'
114        copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
115        copyright += ' * you may not use this file except in compliance with the License.\n'
116        copyright += ' * You may obtain a copy of the License at\n'
117        copyright += ' *\n'
118        copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
119        copyright += ' *\n'
120        copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
121        copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
122        copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
123        copyright += ' * See the License for the specific language governing permissions and\n'
124        copyright += ' * limitations under the License.\n'
125        copyright += ' *\n'
126        copyright += ' * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>\n'
127        copyright += ' * Author: Jon Ashburn <jon@lunarg.com>\n'
128        copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
129        copyright += ' */\n'
130
131        preamble = ''
132        preamble += '#include <vulkan/vulkan.h>\n'
133        preamble += '#include <vulkan/vk_layer.h>\n'
134        preamble += '#include <string.h>\n'
135        preamble += '#include "vk_layer_dispatch_table.h"\n'
136
137        write(copyright, file=self.outFile)
138        write(preamble, file=self.outFile)
139    #
140    # Write generate and write dispatch tables to output file
141    def endFile(self):
142        device_table = ''
143        instance_table = ''
144
145        device_table += self.OutputDispatchTableHelper('device')
146        instance_table += self.OutputDispatchTableHelper('instance')
147
148        for stub in self.dev_ext_stub_list:
149            write(stub, file=self.outFile)
150        write("\n\n", file=self.outFile)
151        write(device_table, file=self.outFile);
152        write("\n", file=self.outFile)
153        write(instance_table, file=self.outFile);
154
155        # Finish processing in superclass
156        OutputGenerator.endFile(self)
157    #
158    # Processing at beginning of each feature or extension
159    def beginFeature(self, interface, emit):
160        OutputGenerator.beginFeature(self, interface, emit)
161        self.featureExtraProtect = GetFeatureProtect(interface)
162        self.extension_type = interface.get('type')
163
164    #
165    # Process commands, adding to appropriate dispatch tables
166    def genCmd(self, cmdinfo, name, alias):
167        OutputGenerator.genCmd(self, cmdinfo, name, alias)
168
169        avoid_entries = ['vkCreateInstance',
170                         'vkCreateDevice']
171        # Get first param type
172        params = cmdinfo.elem.findall('param')
173        info = self.getTypeNameTuple(params[0])
174
175        if name not in avoid_entries:
176            self.AddCommandToDispatchList(name, info[0], self.featureExtraProtect, cmdinfo)
177
178    #
179    # Determine if this API should be ignored or added to the instance or device dispatch table
180    def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo):
181        handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
182        if handle is None:
183            return
184        if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
185            self.device_dispatch_list.append((name, self.featureExtraProtect))
186            if "VK_VERSION" not in self.featureName and self.extension_type == 'device':
187                self.device_extension_list.append(name)
188                # Build up stub function
189                decl = self.makeCDecls(cmdinfo.elem)[1]
190                return_type = cmdinfo.elem.find('proto/type').text
191                return_statement = ""  # default type is void, so no return type
192                try:
193                    return_statement = 'return ' + return_type_table[return_type] + ';'
194                except KeyError:
195                    if return_type != "void":
196                        raise AssertionError("return_type_table does not contain all possible types. Add an entry for `" + return_type + "`.")
197                decl = decl.split('*PFN_vk')[1]
198                decl = decl.replace(')(', '(')
199                decl = 'static VKAPI_ATTR ' + return_type + ' VKAPI_CALL Stub' + decl
200                func_body = ' { ' + return_statement + ' }'
201                decl = decl.replace (';', func_body)
202                if self.featureExtraProtect is not None:
203                    self.dev_ext_stub_list.append('#ifdef %s' % self.featureExtraProtect)
204                self.dev_ext_stub_list.append(decl)
205                if self.featureExtraProtect is not None:
206                    self.dev_ext_stub_list.append('#endif // %s' % self.featureExtraProtect)
207        else:
208            self.instance_dispatch_list.append((name, self.featureExtraProtect))
209        return
210    #
211    # Retrieve the type and name for a parameter
212    def getTypeNameTuple(self, param):
213        type = ''
214        name = ''
215        for elem in param:
216            if elem.tag == 'type':
217                type = noneStr(elem.text)
218            elif elem.tag == 'name':
219                name = noneStr(elem.text)
220        return (type, name)
221    #
222    # Create a dispatch table from the appropriate list and return it as a string
223    def OutputDispatchTableHelper(self, table_type):
224        entries = []
225        table = ''
226        if table_type == 'device':
227            entries = self.device_dispatch_list
228            table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n'
229            table += '    memset(table, 0, sizeof(*table));\n'
230            table += '    table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n\n'
231            table += '    // Device function pointers\n'
232        else:
233            entries = self.instance_dispatch_list
234            table += 'static inline void layer_init_instance_dispatch_table(VkInstance instance, VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa) {\n'
235            table += '    memset(table, 0, sizeof(*table));\n\n'
236            table += '    // Instance function pointers\n'
237
238        for item in entries:
239            # Remove 'vk' from proto name
240            base_name = item[0][2:]
241
242            if item[1] is not None:
243                table += '#ifdef %s\n' % item[1]
244
245            # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
246            # a layer overrides the function name for the loader.
247            if (table_type == 'device' and base_name == 'GetDeviceProcAddr'):
248                table += '    table->GetDeviceProcAddr = gpa;\n'
249            elif (table_type != 'device' and base_name == 'GetInstanceProcAddr'):
250                table += '    table->GetInstanceProcAddr = gpa;\n'
251            else:
252                table += '    table->%s = (PFN_%s) gpa(%s, "%s");\n' % (base_name, item[0], table_type, item[0])
253            if item[0] in self.device_extension_list:
254                stub_check = '    if (table->%s == nullptr) { table->%s = (PFN_%s)Stub%s; }\n' % (base_name, base_name, item[0], base_name)
255                table += stub_check
256            if item[1] is not None:
257                table += '#endif // %s\n' % item[1]
258
259        table += '}'
260        return table
261