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