Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 1 | #!/usr/bin/python3 -i |
| 2 | # |
| 3 | # Copyright (c) 2015-2016 The Khronos Group Inc. |
| 4 | # Copyright (c) 2015-2016 Valve Corporation |
| 5 | # Copyright (c) 2015-2016 LunarG, Inc. |
| 6 | # Copyright (c) 2015-2016 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: Mike Stroyan <stroyan@google.com> |
Mark Lobodzinski | d3b439e | 2017-06-07 13:08:41 -0600 | [diff] [blame] | 21 | # Author: Mark Lobodzinski <mark@lunarg.com> |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 22 | |
| 23 | import os,re,sys |
| 24 | from generator import * |
| 25 | |
| 26 | # ThreadGeneratorOptions - subclass of GeneratorOptions. |
| 27 | # |
| 28 | # Adds options used by ThreadOutputGenerator objects during threading |
| 29 | # layer generation. |
| 30 | # |
| 31 | # Additional members |
| 32 | # prefixText - list of strings to prefix generated header with |
| 33 | # (usually a copyright statement + calling convention macros). |
| 34 | # protectFile - True if multiple inclusion protection should be |
| 35 | # generated (based on the filename) around the entire header. |
| 36 | # protectFeature - True if #ifndef..#endif protection should be |
| 37 | # generated around a feature interface in the header file. |
| 38 | # genFuncPointers - True if function pointer typedefs should be |
| 39 | # generated |
| 40 | # protectProto - If conditional protection should be generated |
| 41 | # around prototype declarations, set to either '#ifdef' |
| 42 | # to require opt-in (#ifdef protectProtoStr) or '#ifndef' |
| 43 | # to require opt-out (#ifndef protectProtoStr). Otherwise |
| 44 | # set to None. |
| 45 | # protectProtoStr - #ifdef/#ifndef symbol to use around prototype |
| 46 | # declarations, if protectProto is set |
| 47 | # apicall - string to use for the function declaration prefix, |
| 48 | # such as APICALL on Windows. |
| 49 | # apientry - string to use for the calling convention macro, |
| 50 | # in typedefs, such as APIENTRY. |
| 51 | # apientryp - string to use for the calling convention macro |
| 52 | # in function pointer typedefs, such as APIENTRYP. |
| 53 | # indentFuncProto - True if prototype declarations should put each |
| 54 | # parameter on a separate line |
| 55 | # indentFuncPointer - True if typedefed function pointers should put each |
| 56 | # parameter on a separate line |
| 57 | # alignFuncParam - if nonzero and parameters are being put on a |
| 58 | # separate line, align parameter names at the specified column |
| 59 | class ThreadGeneratorOptions(GeneratorOptions): |
| 60 | def __init__(self, |
| 61 | filename = None, |
| 62 | directory = '.', |
| 63 | apiname = None, |
| 64 | profile = None, |
| 65 | versions = '.*', |
| 66 | emitversions = '.*', |
| 67 | defaultExtensions = None, |
| 68 | addExtensions = None, |
| 69 | removeExtensions = None, |
| 70 | sortProcedure = regSortFeatures, |
| 71 | prefixText = "", |
| 72 | genFuncPointers = True, |
| 73 | protectFile = True, |
| 74 | protectFeature = True, |
| 75 | protectProto = None, |
| 76 | protectProtoStr = None, |
| 77 | apicall = '', |
| 78 | apientry = '', |
| 79 | apientryp = '', |
| 80 | indentFuncProto = True, |
| 81 | indentFuncPointer = False, |
| 82 | alignFuncParam = 0): |
| 83 | GeneratorOptions.__init__(self, filename, directory, apiname, profile, |
| 84 | versions, emitversions, defaultExtensions, |
| 85 | addExtensions, removeExtensions, sortProcedure) |
| 86 | self.prefixText = prefixText |
| 87 | self.genFuncPointers = genFuncPointers |
| 88 | self.protectFile = protectFile |
| 89 | self.protectFeature = protectFeature |
| 90 | self.protectProto = protectProto |
| 91 | self.protectProtoStr = protectProtoStr |
| 92 | self.apicall = apicall |
| 93 | self.apientry = apientry |
| 94 | self.apientryp = apientryp |
| 95 | self.indentFuncProto = indentFuncProto |
| 96 | self.indentFuncPointer = indentFuncPointer |
| 97 | self.alignFuncParam = alignFuncParam |
| 98 | |
| 99 | # ThreadOutputGenerator - subclass of OutputGenerator. |
| 100 | # Generates Thread checking framework |
| 101 | # |
| 102 | # ---- methods ---- |
| 103 | # ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for |
| 104 | # OutputGenerator. Defines additional internal state. |
| 105 | # ---- methods overriding base class ---- |
| 106 | # beginFile(genOpts) |
| 107 | # endFile() |
| 108 | # beginFeature(interface, emit) |
| 109 | # endFeature() |
| 110 | # genType(typeinfo,name) |
| 111 | # genStruct(typeinfo,name) |
| 112 | # genGroup(groupinfo,name) |
| 113 | # genEnum(enuminfo, name) |
| 114 | # genCmd(cmdinfo) |
| 115 | class ThreadOutputGenerator(OutputGenerator): |
| 116 | """Generate specified API interfaces in a specific style, such as a C header""" |
| 117 | # This is an ordered list of sections in the header file. |
| 118 | TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', |
| 119 | 'group', 'bitmask', 'funcpointer', 'struct'] |
| 120 | ALL_SECTIONS = TYPE_SECTIONS + ['command'] |
| 121 | def __init__(self, |
| 122 | errFile = sys.stderr, |
| 123 | warnFile = sys.stderr, |
| 124 | diagFile = sys.stdout): |
| 125 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) |
| 126 | # Internal state - accumulators for different inner block text |
| 127 | self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) |
| 128 | self.intercepts = [] |
| 129 | |
| 130 | # Check if the parameter passed in is a pointer to an array |
| 131 | def paramIsArray(self, param): |
| 132 | return param.attrib.get('len') is not None |
| 133 | |
| 134 | # Check if the parameter passed in is a pointer |
| 135 | def paramIsPointer(self, param): |
| 136 | ispointer = False |
| 137 | for elem in param: |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 138 | if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail: |
| 139 | ispointer = True |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 140 | return ispointer |
Mark Lobodzinski | 60b77b3 | 2017-02-14 09:16:56 -0700 | [diff] [blame] | 141 | |
| 142 | # Check if an object is a non-dispatchable handle |
| 143 | def isHandleTypeNonDispatchable(self, handletype): |
| 144 | handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") |
| 145 | if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': |
| 146 | return True |
| 147 | else: |
| 148 | return False |
| 149 | |
| 150 | # Check if an object is a dispatchable handle |
| 151 | def isHandleTypeDispatchable(self, handletype): |
| 152 | handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") |
| 153 | if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE': |
| 154 | return True |
| 155 | else: |
| 156 | return False |
| 157 | |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 158 | def makeThreadUseBlock(self, cmd, functionprefix): |
| 159 | """Generate C function pointer typedef for <command> Element""" |
| 160 | paramdecl = '' |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 161 | # Find and add any parameters that are thread unsafe |
| 162 | params = cmd.findall('param') |
| 163 | for param in params: |
| 164 | paramname = param.find('name') |
| 165 | if False: # self.paramIsPointer(param): |
| 166 | paramdecl += ' // not watching use of pointer ' + paramname.text + '\n' |
| 167 | else: |
| 168 | externsync = param.attrib.get('externsync') |
| 169 | if externsync == 'true': |
| 170 | if self.paramIsArray(param): |
| 171 | paramdecl += ' for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n' |
| 172 | paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + '[index]);\n' |
| 173 | paramdecl += ' }\n' |
| 174 | else: |
| 175 | paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + ');\n' |
| 176 | elif (param.attrib.get('externsync')): |
| 177 | if self.paramIsArray(param): |
| 178 | # Externsync can list pointers to arrays of members to synchronize |
| 179 | paramdecl += ' for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n' |
| 180 | for member in externsync.split(","): |
| 181 | # Replace first empty [] in member name with index |
| 182 | element = member.replace('[]','[index]',1) |
| 183 | if '[]' in element: |
| 184 | # Replace any second empty [] in element name with |
| 185 | # inner array index based on mapping array names like |
| 186 | # "pSomeThings[]" to "someThingCount" array size. |
| 187 | # This could be more robust by mapping a param member |
| 188 | # name to a struct type and "len" attribute. |
| 189 | limit = element[0:element.find('s[]')] + 'Count' |
| 190 | dotp = limit.rfind('.p') |
| 191 | limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:] |
| 192 | paramdecl += ' for(uint32_t index2=0;index2<'+limit+';index2++)\n' |
| 193 | element = element.replace('[]','[index2]') |
| 194 | paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + element + ');\n' |
| 195 | paramdecl += ' }\n' |
| 196 | else: |
| 197 | # externsync can list members to synchronize |
| 198 | for member in externsync.split(","): |
| 199 | member = str(member).replace("::", "->") |
Mark Lobodzinski | 9c14780 | 2017-02-10 08:34:54 -0700 | [diff] [blame] | 200 | member = str(member).replace(".", "->") |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 201 | paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + member + ');\n' |
| 202 | else: |
| 203 | paramtype = param.find('type') |
| 204 | if paramtype is not None: |
| 205 | paramtype = paramtype.text |
| 206 | else: |
| 207 | paramtype = 'None' |
Mark Lobodzinski | 60b77b3 | 2017-02-14 09:16:56 -0700 | [diff] [blame] | 208 | if (self.isHandleTypeDispatchable(paramtype) or self.isHandleTypeNonDispatchable(paramtype)) and paramtype != 'VkPhysicalDevice': |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 209 | if self.paramIsArray(param) and ('pPipelines' != paramname.text): |
Mark Lobodzinski | 9c14780 | 2017-02-10 08:34:54 -0700 | [diff] [blame] | 210 | # Add pointer dereference for array counts that are pointer values |
| 211 | dereference = '' |
| 212 | for candidate in params: |
| 213 | if param.attrib.get('len') == candidate.find('name').text: |
| 214 | if self.paramIsPointer(candidate): |
| 215 | dereference = '*' |
Mark Lobodzinski | 60b77b3 | 2017-02-14 09:16:56 -0700 | [diff] [blame] | 216 | param_len = str(param.attrib.get('len')).replace("::", "->") |
| 217 | paramdecl += ' for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n' |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 218 | paramdecl += ' ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + '[index]);\n' |
| 219 | paramdecl += ' }\n' |
| 220 | elif not self.paramIsPointer(param): |
| 221 | # Pointer params are often being created. |
| 222 | # They are not being read from. |
| 223 | paramdecl += ' ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + ');\n' |
| 224 | explicitexternsyncparams = cmd.findall("param[@externsync]") |
| 225 | if (explicitexternsyncparams is not None): |
| 226 | for param in explicitexternsyncparams: |
| 227 | externsyncattrib = param.attrib.get('externsync') |
| 228 | paramname = param.find('name') |
| 229 | paramdecl += ' // Host access to ' |
| 230 | if externsyncattrib == 'true': |
| 231 | if self.paramIsArray(param): |
| 232 | paramdecl += 'each member of ' + paramname.text |
| 233 | elif self.paramIsPointer(param): |
| 234 | paramdecl += 'the object referenced by ' + paramname.text |
| 235 | else: |
| 236 | paramdecl += paramname.text |
| 237 | else: |
| 238 | paramdecl += externsyncattrib |
| 239 | paramdecl += ' must be externally synchronized\n' |
| 240 | |
| 241 | # Find and add any "implicit" parameters that are thread unsafe |
| 242 | implicitexternsyncparams = cmd.find('implicitexternsyncparams') |
| 243 | if (implicitexternsyncparams is not None): |
| 244 | for elem in implicitexternsyncparams: |
| 245 | paramdecl += ' // ' |
| 246 | paramdecl += elem.text |
| 247 | paramdecl += ' must be externally synchronized between host accesses\n' |
| 248 | |
| 249 | if (paramdecl == ''): |
| 250 | return None |
| 251 | else: |
| 252 | return paramdecl |
| 253 | def beginFile(self, genOpts): |
| 254 | OutputGenerator.beginFile(self, genOpts) |
| 255 | # C-specific |
| 256 | # |
| 257 | # Multiple inclusion protection & C++ namespace. |
| 258 | if (genOpts.protectFile and self.genOpts.filename): |
| 259 | headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename)) |
| 260 | write('#ifndef', headerSym, file=self.outFile) |
| 261 | write('#define', headerSym, '1', file=self.outFile) |
| 262 | self.newline() |
| 263 | write('namespace threading {', file=self.outFile) |
| 264 | self.newline() |
| 265 | # |
| 266 | # User-supplied prefix text, if any (list of strings) |
| 267 | if (genOpts.prefixText): |
| 268 | for s in genOpts.prefixText: |
| 269 | write(s, file=self.outFile) |
| 270 | def endFile(self): |
| 271 | # C-specific |
| 272 | # Finish C++ namespace and multiple inclusion protection |
| 273 | self.newline() |
| 274 | # record intercepted procedures |
Mark Lobodzinski | d3b439e | 2017-06-07 13:08:41 -0600 | [diff] [blame] | 275 | write('// Map of all APIs to be intercepted by this layer', file=self.outFile) |
| 276 | write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile) |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 277 | write('\n'.join(self.intercepts), file=self.outFile) |
| 278 | write('};\n', file=self.outFile) |
| 279 | self.newline() |
| 280 | write('} // namespace threading', file=self.outFile) |
| 281 | if (self.genOpts.protectFile and self.genOpts.filename): |
| 282 | self.newline() |
| 283 | write('#endif', file=self.outFile) |
| 284 | # Finish processing in superclass |
| 285 | OutputGenerator.endFile(self) |
| 286 | def beginFeature(self, interface, emit): |
| 287 | #write('// starting beginFeature', file=self.outFile) |
| 288 | # Start processing in superclass |
| 289 | OutputGenerator.beginFeature(self, interface, emit) |
| 290 | # C-specific |
| 291 | # Accumulate includes, defines, types, enums, function pointer typedefs, |
| 292 | # end function prototypes separately for this feature. They're only |
| 293 | # printed in endFeature(). |
| 294 | self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) |
| 295 | #write('// ending beginFeature', file=self.outFile) |
| 296 | def endFeature(self): |
| 297 | # C-specific |
| 298 | # Actually write the interface to the output file. |
| 299 | #write('// starting endFeature', file=self.outFile) |
| 300 | if (self.emit): |
| 301 | self.newline() |
| 302 | if (self.genOpts.protectFeature): |
| 303 | write('#ifndef', self.featureName, file=self.outFile) |
| 304 | # If type declarations are needed by other features based on |
| 305 | # this one, it may be necessary to suppress the ExtraProtect, |
| 306 | # or move it below the 'for section...' loop. |
| 307 | #write('// endFeature looking at self.featureExtraProtect', file=self.outFile) |
| 308 | if (self.featureExtraProtect != None): |
| 309 | write('#ifdef', self.featureExtraProtect, file=self.outFile) |
| 310 | #write('#define', self.featureName, '1', file=self.outFile) |
| 311 | for section in self.TYPE_SECTIONS: |
| 312 | #write('// endFeature writing section'+section, file=self.outFile) |
| 313 | contents = self.sections[section] |
| 314 | if contents: |
| 315 | write('\n'.join(contents), file=self.outFile) |
| 316 | self.newline() |
| 317 | #write('// endFeature looking at self.sections[command]', file=self.outFile) |
| 318 | if (self.sections['command']): |
Jamie Madill | 24aa974 | 2016-12-13 17:02:57 -0500 | [diff] [blame] | 319 | write('\n'.join(self.sections['command']), end=u'', file=self.outFile) |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 320 | self.newline() |
| 321 | if (self.featureExtraProtect != None): |
| 322 | write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) |
| 323 | if (self.genOpts.protectFeature): |
| 324 | write('#endif /*', self.featureName, '*/', file=self.outFile) |
| 325 | # Finish processing in superclass |
| 326 | OutputGenerator.endFeature(self) |
| 327 | #write('// ending endFeature', file=self.outFile) |
| 328 | # |
| 329 | # Append a definition to the specified section |
| 330 | def appendSection(self, section, text): |
| 331 | # self.sections[section].append('SECTION: ' + section + '\n') |
| 332 | self.sections[section].append(text) |
| 333 | # |
| 334 | # Type generation |
| 335 | def genType(self, typeinfo, name): |
| 336 | pass |
| 337 | # |
| 338 | # Struct (e.g. C "struct" type) generation. |
| 339 | # This is a special case of the <type> tag where the contents are |
| 340 | # interpreted as a set of <member> tags instead of freeform C |
| 341 | # C type declarations. The <member> tags are just like <param> |
| 342 | # tags - they are a declaration of a struct or union member. |
| 343 | # Only simple member declarations are supported (no nested |
| 344 | # structs etc.) |
| 345 | def genStruct(self, typeinfo, typeName): |
| 346 | OutputGenerator.genStruct(self, typeinfo, typeName) |
| 347 | body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n' |
| 348 | # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam) |
| 349 | for member in typeinfo.elem.findall('.//member'): |
| 350 | body += self.makeCParamDecl(member, self.genOpts.alignFuncParam) |
| 351 | body += ';\n' |
| 352 | body += '} ' + typeName + ';\n' |
| 353 | self.appendSection('struct', body) |
| 354 | # |
| 355 | # Group (e.g. C "enum" type) generation. |
| 356 | # These are concatenated together with other types. |
| 357 | def genGroup(self, groupinfo, groupName): |
| 358 | pass |
| 359 | # Enumerant generation |
| 360 | # <enum> tags may specify their values in several ways, but are usually |
| 361 | # just integers. |
| 362 | def genEnum(self, enuminfo, name): |
| 363 | pass |
| 364 | # |
| 365 | # Command generation |
| 366 | def genCmd(self, cmdinfo, name): |
| 367 | # Commands shadowed by interface functions and are not implemented |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 368 | special_functions = [ |
| 369 | 'vkGetDeviceProcAddr', |
| 370 | 'vkGetInstanceProcAddr', |
| 371 | 'vkCreateDevice', |
| 372 | 'vkDestroyDevice', |
| 373 | 'vkCreateInstance', |
| 374 | 'vkDestroyInstance', |
| 375 | 'vkAllocateCommandBuffers', |
| 376 | 'vkFreeCommandBuffers', |
| 377 | 'vkCreateDebugReportCallbackEXT', |
| 378 | 'vkDestroyDebugReportCallbackEXT', |
Mark Lobodzinski | 3bd82ad | 2017-02-16 11:45:27 -0700 | [diff] [blame] | 379 | 'vkAllocateDescriptorSets', |
Mark Lobodzinski | df47c5a | 2017-02-28 15:09:31 -0700 | [diff] [blame] | 380 | 'vkGetSwapchainImagesKHR', |
Mark Lobodzinski | d3b439e | 2017-06-07 13:08:41 -0600 | [diff] [blame] | 381 | 'vkEnumerateInstanceLayerProperties', |
| 382 | 'vkEnumerateInstanceExtensionProperties', |
| 383 | 'vkEnumerateDeviceLayerProperties', |
| 384 | 'vkEnumerateDeviceExtensionProperties', |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 385 | ] |
| 386 | if name in special_functions: |
| 387 | decls = self.makeCDecls(cmdinfo.elem) |
| 388 | self.appendSection('command', '') |
| 389 | self.appendSection('command', '// declare only') |
| 390 | self.appendSection('command', decls[0]) |
Mark Lobodzinski | d3b439e | 2017-06-07 13:08:41 -0600 | [diff] [blame] | 391 | self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 392 | return |
Mark Lobodzinski | 9c14780 | 2017-02-10 08:34:54 -0700 | [diff] [blame] | 393 | if "QueuePresentKHR" in name or ("DebugMarker" in name and "EXT" in name): |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 394 | self.appendSection('command', '// TODO - not wrapping EXT function ' + name) |
| 395 | return |
| 396 | # Determine first if this function needs to be intercepted |
| 397 | startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'start') |
| 398 | if startthreadsafety is None: |
| 399 | return |
| 400 | finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'finish') |
| 401 | # record that the function will be intercepted |
| 402 | if (self.featureExtraProtect != None): |
| 403 | self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] |
Mark Lobodzinski | d3b439e | 2017-06-07 13:08:41 -0600 | [diff] [blame] | 404 | self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 405 | if (self.featureExtraProtect != None): |
| 406 | self.intercepts += [ '#endif' ] |
| 407 | |
| 408 | OutputGenerator.genCmd(self, cmdinfo, name) |
| 409 | # |
| 410 | decls = self.makeCDecls(cmdinfo.elem) |
| 411 | self.appendSection('command', '') |
| 412 | self.appendSection('command', decls[0][:-1]) |
| 413 | self.appendSection('command', '{') |
| 414 | # setup common to call wrappers |
| 415 | # first parameter is always dispatchable |
| 416 | dispatchable_type = cmdinfo.elem.find('param/type').text |
| 417 | dispatchable_name = cmdinfo.elem.find('param/name').text |
| 418 | self.appendSection('command', ' dispatch_key key = get_dispatch_key('+dispatchable_name+');') |
Tobin Ehlis | 8d6acde | 2017-02-08 07:40:40 -0700 | [diff] [blame] | 419 | self.appendSection('command', ' layer_data *my_data = GetLayerDataPtr(key, layer_data_map);') |
Mark Lobodzinski | ff91099 | 2016-10-11 14:29:52 -0600 | [diff] [blame] | 420 | if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]: |
| 421 | self.appendSection('command', ' VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;') |
| 422 | else: |
| 423 | self.appendSection('command', ' VkLayerDispatchTable *pTable = my_data->device_dispatch_table;') |
| 424 | # Declare result variable, if any. |
| 425 | resulttype = cmdinfo.elem.find('proto/type') |
| 426 | if (resulttype != None and resulttype.text == 'void'): |
| 427 | resulttype = None |
| 428 | if (resulttype != None): |
| 429 | self.appendSection('command', ' ' + resulttype.text + ' result;') |
| 430 | assignresult = 'result = ' |
| 431 | else: |
| 432 | assignresult = '' |
| 433 | |
| 434 | self.appendSection('command', ' bool threadChecks = startMultiThread();') |
| 435 | self.appendSection('command', ' if (threadChecks) {') |
| 436 | self.appendSection('command', " "+"\n ".join(str(startthreadsafety).rstrip().split("\n"))) |
| 437 | self.appendSection('command', ' }') |
| 438 | params = cmdinfo.elem.findall('param/name') |
| 439 | paramstext = ','.join([str(param.text) for param in params]) |
| 440 | API = cmdinfo.elem.attrib.get('name').replace('vk','pTable->',1) |
| 441 | self.appendSection('command', ' ' + assignresult + API + '(' + paramstext + ');') |
| 442 | self.appendSection('command', ' if (threadChecks) {') |
| 443 | self.appendSection('command', " "+"\n ".join(str(finishthreadsafety).rstrip().split("\n"))) |
| 444 | self.appendSection('command', ' } else {') |
| 445 | self.appendSection('command', ' finishMultiThread();') |
| 446 | self.appendSection('command', ' }') |
| 447 | # Return result variable, if any. |
| 448 | if (resulttype != None): |
| 449 | self.appendSection('command', ' return result;') |
| 450 | self.appendSection('command', '}') |
| 451 | # |
| 452 | # override makeProtoName to drop the "vk" prefix |
| 453 | def makeProtoName(self, name, tail): |
| 454 | return self.genOpts.apientry + name[2:] + tail |