diff options
Diffstat (limited to 'scripts/threading_generator.py')
-rw-r--r-- | scripts/threading_generator.py | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py deleted file mode 100644 index 5cfb4d7bd..000000000 --- a/scripts/threading_generator.py +++ /dev/null @@ -1,458 +0,0 @@ -#!/usr/bin/python3 -i -# -# Copyright (c) 2015-2016 The Khronos Group Inc. -# Copyright (c) 2015-2016 Valve Corporation -# Copyright (c) 2015-2016 LunarG, Inc. -# Copyright (c) 2015-2016 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Mike Stroyan <stroyan@google.com> -# Author: Mark Lobodzinski <mark@lunarg.com> - -import os,re,sys -from generator import * -from common_codegen import * - -# ThreadGeneratorOptions - subclass of GeneratorOptions. -# -# Adds options used by ThreadOutputGenerator objects during threading -# layer generation. -# -# Additional members -# prefixText - list of strings to prefix generated header with -# (usually a copyright statement + calling convention macros). -# protectFile - True if multiple inclusion protection should be -# generated (based on the filename) around the entire header. -# protectFeature - True if #ifndef..#endif protection should be -# generated around a feature interface in the header file. -# genFuncPointers - True if function pointer typedefs should be -# generated -# protectProto - If conditional protection should be generated -# around prototype declarations, set to either '#ifdef' -# to require opt-in (#ifdef protectProtoStr) or '#ifndef' -# to require opt-out (#ifndef protectProtoStr). Otherwise -# set to None. -# protectProtoStr - #ifdef/#ifndef symbol to use around prototype -# declarations, if protectProto is set -# apicall - string to use for the function declaration prefix, -# such as APICALL on Windows. -# apientry - string to use for the calling convention macro, -# in typedefs, such as APIENTRY. -# apientryp - string to use for the calling convention macro -# in function pointer typedefs, such as APIENTRYP. -# indentFuncProto - True if prototype declarations should put each -# parameter on a separate line -# indentFuncPointer - True if typedefed function pointers should put each -# parameter on a separate line -# alignFuncParam - if nonzero and parameters are being put on a -# separate line, align parameter names at the specified column -class ThreadGeneratorOptions(GeneratorOptions): - def __init__(self, - filename = None, - directory = '.', - apiname = None, - profile = None, - versions = '.*', - emitversions = '.*', - defaultExtensions = None, - addExtensions = None, - removeExtensions = None, - emitExtensions = None, - sortProcedure = regSortFeatures, - prefixText = "", - genFuncPointers = True, - protectFile = True, - protectFeature = True, - apicall = '', - apientry = '', - apientryp = '', - indentFuncProto = True, - indentFuncPointer = False, - alignFuncParam = 0, - expandEnumerants = True): - GeneratorOptions.__init__(self, filename, directory, apiname, profile, - versions, emitversions, defaultExtensions, - addExtensions, removeExtensions, emitExtensions, sortProcedure) - self.prefixText = prefixText - self.genFuncPointers = genFuncPointers - self.protectFile = protectFile - self.protectFeature = protectFeature - self.apicall = apicall - self.apientry = apientry - self.apientryp = apientryp - self.indentFuncProto = indentFuncProto - self.indentFuncPointer = indentFuncPointer - self.alignFuncParam = alignFuncParam - self.expandEnumerants = expandEnumerants - - -# ThreadOutputGenerator - subclass of OutputGenerator. -# Generates Thread checking framework -# -# ---- methods ---- -# ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for -# OutputGenerator. Defines additional internal state. -# ---- methods overriding base class ---- -# beginFile(genOpts) -# endFile() -# beginFeature(interface, emit) -# endFeature() -# genType(typeinfo,name) -# genStruct(typeinfo,name) -# genGroup(groupinfo,name) -# genEnum(enuminfo, name) -# genCmd(cmdinfo) -class ThreadOutputGenerator(OutputGenerator): - """Generate specified API interfaces in a specific style, such as a C header""" - # This is an ordered list of sections in the header file. - TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', - 'group', 'bitmask', 'funcpointer', 'struct'] - ALL_SECTIONS = TYPE_SECTIONS + ['command'] - def __init__(self, - errFile = sys.stderr, - warnFile = sys.stderr, - diagFile = sys.stdout): - OutputGenerator.__init__(self, errFile, warnFile, diagFile) - # Internal state - accumulators for different inner block text - self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) - self.intercepts = [] - - # Check if the parameter passed in is a pointer to an array - def paramIsArray(self, param): - return param.attrib.get('len') is not None - - # Check if the parameter passed in is a pointer - def paramIsPointer(self, param): - ispointer = False - for elem in param: - if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail: - ispointer = True - return ispointer - - # Check if an object is a non-dispatchable handle - def isHandleTypeNonDispatchable(self, handletype): - handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") - if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': - return True - else: - return False - - # Check if an object is a dispatchable handle - def isHandleTypeDispatchable(self, handletype): - handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") - if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE': - return True - else: - return False - - def makeThreadUseBlock(self, cmd, functionprefix): - """Generate C function pointer typedef for <command> Element""" - paramdecl = '' - # Find and add any parameters that are thread unsafe - params = cmd.findall('param') - for param in params: - paramname = param.find('name') - if False: # self.paramIsPointer(param): - paramdecl += ' // not watching use of pointer ' + paramname.text + '\n' - else: - externsync = param.attrib.get('externsync') - if externsync == 'true': - if self.paramIsArray(param): - paramdecl += ' for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n' - paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + '[index]);\n' - paramdecl += ' }\n' - else: - paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + paramname.text + ');\n' - elif (param.attrib.get('externsync')): - if self.paramIsArray(param): - # Externsync can list pointers to arrays of members to synchronize - paramdecl += ' for (uint32_t index=0;index<' + param.attrib.get('len') + ';index++) {\n' - for member in externsync.split(","): - # Replace first empty [] in member name with index - element = member.replace('[]','[index]',1) - if '[]' in element: - # Replace any second empty [] in element name with - # inner array index based on mapping array names like - # "pSomeThings[]" to "someThingCount" array size. - # This could be more robust by mapping a param member - # name to a struct type and "len" attribute. - limit = element[0:element.find('s[]')] + 'Count' - dotp = limit.rfind('.p') - limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:] - paramdecl += ' for(uint32_t index2=0;index2<'+limit+';index2++)\n' - element = element.replace('[]','[index2]') - paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + element + ');\n' - paramdecl += ' }\n' - else: - # externsync can list members to synchronize - for member in externsync.split(","): - member = str(member).replace("::", "->") - member = str(member).replace(".", "->") - paramdecl += ' ' + functionprefix + 'WriteObject(my_data, ' + member + ');\n' - else: - paramtype = param.find('type') - if paramtype is not None: - paramtype = paramtype.text - else: - paramtype = 'None' - if (self.isHandleTypeDispatchable(paramtype) or self.isHandleTypeNonDispatchable(paramtype)) and paramtype != 'VkPhysicalDevice': - if self.paramIsArray(param) and ('pPipelines' != paramname.text): - # Add pointer dereference for array counts that are pointer values - dereference = '' - for candidate in params: - if param.attrib.get('len') == candidate.find('name').text: - if self.paramIsPointer(candidate): - dereference = '*' - param_len = str(param.attrib.get('len')).replace("::", "->") - paramdecl += ' for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n' - paramdecl += ' ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + '[index]);\n' - paramdecl += ' }\n' - elif not self.paramIsPointer(param): - # Pointer params are often being created. - # They are not being read from. - paramdecl += ' ' + functionprefix + 'ReadObject(my_data, ' + paramname.text + ');\n' - explicitexternsyncparams = cmd.findall("param[@externsync]") - if (explicitexternsyncparams is not None): - for param in explicitexternsyncparams: - externsyncattrib = param.attrib.get('externsync') - paramname = param.find('name') - paramdecl += ' // Host access to ' - if externsyncattrib == 'true': - if self.paramIsArray(param): - paramdecl += 'each member of ' + paramname.text - elif self.paramIsPointer(param): - paramdecl += 'the object referenced by ' + paramname.text - else: - paramdecl += paramname.text - else: - paramdecl += externsyncattrib - paramdecl += ' must be externally synchronized\n' - - # Find and add any "implicit" parameters that are thread unsafe - implicitexternsyncparams = cmd.find('implicitexternsyncparams') - if (implicitexternsyncparams is not None): - for elem in implicitexternsyncparams: - paramdecl += ' // ' - paramdecl += elem.text - paramdecl += ' must be externally synchronized between host accesses\n' - - if (paramdecl == ''): - return None - else: - return paramdecl - def beginFile(self, genOpts): - OutputGenerator.beginFile(self, genOpts) - # C-specific - # - # Multiple inclusion protection & C++ namespace. - if (genOpts.protectFile and self.genOpts.filename): - headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename)) - write('#ifndef', headerSym, file=self.outFile) - write('#define', headerSym, '1', file=self.outFile) - self.newline() - write('namespace threading {', file=self.outFile) - self.newline() - # - # User-supplied prefix text, if any (list of strings) - if (genOpts.prefixText): - for s in genOpts.prefixText: - write(s, file=self.outFile) - def endFile(self): - # C-specific - # Finish C++ namespace and multiple inclusion protection - self.newline() - # record intercepted procedures - write('// Map of all APIs to be intercepted by this layer', file=self.outFile) - write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile) - write('\n'.join(self.intercepts), file=self.outFile) - write('};\n', file=self.outFile) - self.newline() - write('} // namespace threading', file=self.outFile) - if (self.genOpts.protectFile and self.genOpts.filename): - self.newline() - write('#endif', file=self.outFile) - # Finish processing in superclass - OutputGenerator.endFile(self) - def beginFeature(self, interface, emit): - #write('// starting beginFeature', file=self.outFile) - # Start processing in superclass - OutputGenerator.beginFeature(self, interface, emit) - # C-specific - # Accumulate includes, defines, types, enums, function pointer typedefs, - # end function prototypes separately for this feature. They're only - # printed in endFeature(). - self.featureExtraProtect = GetFeatureProtect(interface) - self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) - #write('// ending beginFeature', file=self.outFile) - def endFeature(self): - # C-specific - # Actually write the interface to the output file. - #write('// starting endFeature', file=self.outFile) - if (self.emit): - self.newline() - if (self.genOpts.protectFeature): - write('#ifndef', self.featureName, file=self.outFile) - # If type declarations are needed by other features based on - # this one, it may be necessary to suppress the ExtraProtect, - # or move it below the 'for section...' loop. - #write('// endFeature looking at self.featureExtraProtect', file=self.outFile) - if (self.featureExtraProtect != None): - write('#ifdef', self.featureExtraProtect, file=self.outFile) - #write('#define', self.featureName, '1', file=self.outFile) - for section in self.TYPE_SECTIONS: - #write('// endFeature writing section'+section, file=self.outFile) - contents = self.sections[section] - if contents: - write('\n'.join(contents), file=self.outFile) - self.newline() - #write('// endFeature looking at self.sections[command]', file=self.outFile) - if (self.sections['command']): - write('\n'.join(self.sections['command']), end=u'', file=self.outFile) - self.newline() - if (self.featureExtraProtect != None): - write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) - if (self.genOpts.protectFeature): - write('#endif /*', self.featureName, '*/', file=self.outFile) - # Finish processing in superclass - OutputGenerator.endFeature(self) - #write('// ending endFeature', file=self.outFile) - # - # Append a definition to the specified section - def appendSection(self, section, text): - # self.sections[section].append('SECTION: ' + section + '\n') - self.sections[section].append(text) - # - # Type generation - def genType(self, typeinfo, name, alias): - pass - # - # Struct (e.g. C "struct" type) generation. - # This is a special case of the <type> tag where the contents are - # interpreted as a set of <member> tags instead of freeform C - # C type declarations. The <member> tags are just like <param> - # tags - they are a declaration of a struct or union member. - # Only simple member declarations are supported (no nested - # structs etc.) - def genStruct(self, typeinfo, typeName, alias): - OutputGenerator.genStruct(self, typeinfo, typeName, alias) - body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n' - # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam) - for member in typeinfo.elem.findall('.//member'): - body += self.makeCParamDecl(member, self.genOpts.alignFuncParam) - body += ';\n' - body += '} ' + typeName + ';\n' - self.appendSection('struct', body) - # - # Group (e.g. C "enum" type) generation. - # These are concatenated together with other types. - def genGroup(self, groupinfo, groupName, alias): - pass - # Enumerant generation - # <enum> tags may specify their values in several ways, but are usually - # just integers. - def genEnum(self, enuminfo, name, alias): - pass - # - # Command generation - def genCmd(self, cmdinfo, name, alias): - # Commands shadowed by interface functions and are not implemented - special_functions = [ - 'vkGetDeviceProcAddr', - 'vkGetInstanceProcAddr', - 'vkCreateDevice', - 'vkDestroyDevice', - 'vkCreateInstance', - 'vkDestroyInstance', - 'vkAllocateCommandBuffers', - 'vkFreeCommandBuffers', - 'vkCreateDebugReportCallbackEXT', - 'vkDestroyDebugReportCallbackEXT', - 'vkAllocateDescriptorSets', - 'vkGetSwapchainImagesKHR', - 'vkEnumerateInstanceLayerProperties', - 'vkEnumerateInstanceExtensionProperties', - 'vkEnumerateDeviceLayerProperties', - 'vkEnumerateDeviceExtensionProperties', - 'vkCreateDebugUtilsMessengerEXT', - 'vkDestroyDebugUtilsMessengerEXT', - ] - if name in special_functions: - decls = self.makeCDecls(cmdinfo.elem) - self.appendSection('command', '') - self.appendSection('command', '// declare only') - self.appendSection('command', decls[0]) - self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] - return - if "QueuePresentKHR" in name or (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name): - self.appendSection('command', '// TODO - not wrapping EXT function ' + name) - return - # Determine first if this function needs to be intercepted - startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'start') - if startthreadsafety is None: - return - finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'finish') - # record that the function will be intercepted - if (self.featureExtraProtect != None): - self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] - self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] - if (self.featureExtraProtect != None): - self.intercepts += [ '#endif' ] - - OutputGenerator.genCmd(self, cmdinfo, name, alias) - # - decls = self.makeCDecls(cmdinfo.elem) - self.appendSection('command', '') - self.appendSection('command', decls[0][:-1]) - self.appendSection('command', '{') - # setup common to call wrappers - # first parameter is always dispatchable - dispatchable_type = cmdinfo.elem.find('param/type').text - dispatchable_name = cmdinfo.elem.find('param/name').text - self.appendSection('command', ' dispatch_key key = get_dispatch_key('+dispatchable_name+');') - self.appendSection('command', ' layer_data *my_data = GetLayerDataPtr(key, layer_data_map);') - if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]: - self.appendSection('command', ' VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;') - else: - self.appendSection('command', ' VkLayerDispatchTable *pTable = my_data->device_dispatch_table;') - # Declare result variable, if any. - resulttype = cmdinfo.elem.find('proto/type') - if (resulttype != None and resulttype.text == 'void'): - resulttype = None - if (resulttype != None): - self.appendSection('command', ' ' + resulttype.text + ' result;') - assignresult = 'result = ' - else: - assignresult = '' - - self.appendSection('command', ' bool threadChecks = startMultiThread();') - self.appendSection('command', ' if (threadChecks) {') - self.appendSection('command', " "+"\n ".join(str(startthreadsafety).rstrip().split("\n"))) - self.appendSection('command', ' }') - params = cmdinfo.elem.findall('param/name') - paramstext = ','.join([str(param.text) for param in params]) - API = cmdinfo.elem.attrib.get('name').replace('vk','pTable->',1) - self.appendSection('command', ' ' + assignresult + API + '(' + paramstext + ');') - self.appendSection('command', ' if (threadChecks) {') - self.appendSection('command', " "+"\n ".join(str(finishthreadsafety).rstrip().split("\n"))) - self.appendSection('command', ' } else {') - self.appendSection('command', ' finishMultiThread();') - self.appendSection('command', ' }') - # Return result variable, if any. - if (resulttype != None): - self.appendSection('command', ' return result;') - self.appendSection('command', '}') - # - # override makeProtoName to drop the "vk" prefix - def makeProtoName(self, name, tail): - return self.genOpts.apientry + name[2:] + tail |