#!/usr/bin/python3 -i # # Copyright (c) 2013-2019 The Khronos Group 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. import re import sys from generator import OutputGenerator, write # HostSynchronizationOutputGenerator - subclass of OutputGenerator. # Generates AsciiDoc includes of the externsync parameter table for the # fundamentals chapter of the API specification. Similar to # DocOutputGenerator. # # ---- methods ---- # HostSynchronizationOutputGenerator(errFile, warnFile, diagFile) - args as for # OutputGenerator. Defines additional internal state. # ---- methods overriding base class ---- # genCmd(cmdinfo) class HostSynchronizationOutputGenerator(OutputGenerator): # Generate Host Synchronized Parameters in a table at the top of the spec def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) threadsafety = {'parameters': '', 'parameterlists': '', 'implicit': ''} def makeParameterName(self, name): return 'pname:' + name def makeFLink(self, name): return 'flink:' + name # Generate an include file # # directory - subdirectory to put file in # basename - base name of the file # contents - contents of the file (Asciidoc boilerplate aside) def writeInclude(self): if self.threadsafety['parameters'] is not None: # Create file filename = self.genOpts.directory + '/' + 'parameters.txt' self.logMsg('diag', '# Generating include file:', filename) fp = open(filename, 'w', encoding='utf-8') # Host Synchronization write(self.genOpts.conventions.warning_comment, file=fp) write('.Externally Synchronized Parameters', file=fp) write('****', file=fp) write(self.threadsafety['parameters'], file=fp, end='') write('****', file=fp) write('', file=fp) if self.threadsafety['parameterlists'] is not None: # Create file filename = self.genOpts.directory + '/' + '/parameterlists.txt' self.logMsg('diag', '# Generating include file:', filename) fp = open(filename, 'w', encoding='utf-8') # Host Synchronization write(self.genOpts.conventions.warning_comment, file=fp) write('.Externally Synchronized Parameter Lists', file=fp) write('****', file=fp) write(self.threadsafety['parameterlists'], file=fp, end='') write('****', file=fp) write('', file=fp) if self.threadsafety['implicit'] is not None: # Create file filename = self.genOpts.directory + '/' + '/implicit.txt' self.logMsg('diag', '# Generating include file:', filename) fp = open(filename, 'w', encoding='utf-8') # Host Synchronization write(self.genOpts.conventions.warning_comment, file=fp) write('.Implicit Externally Synchronized Parameters', file=fp) write('****', file=fp) write(self.threadsafety['implicit'], file=fp, end='') write('****', file=fp) write('', file=fp) fp.close() # Check if the parameter passed in is a pointer to an array def paramIsArray(self, param): return param.get('len') is not None # Check if the parameter passed in is a pointer def paramIsPointer(self, param): ispointer = False paramtype = param.find('type') if paramtype.tail is not None and '*' in paramtype.tail: ispointer = True return ispointer # Turn the "name[].member[]" notation into plain English. def makeThreadDereferenceHumanReadable(self, dereference): matches = re.findall(r"[\w]+[^\w]*",dereference) stringval = '' for match in reversed(matches): if '->' in match or '.' in match: stringval += 'member of ' if '[]' in match: stringval += 'each element of ' stringval += 'the ' stringval += self.makeParameterName(re.findall(r"[\w]+",match)[0]) stringval += ' ' stringval += 'parameter' return stringval[0].upper() + stringval[1:] def makeThreadSafetyBlocks(self, cmd, paramtext): protoname = cmd.find('proto/name').text # Find and add any parameters that are thread unsafe explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]") if explicitexternsyncparams is not None: for param in explicitexternsyncparams: externsyncattribs = param.get('externsync') paramname = param.find('name') for externsyncattrib in externsyncattribs.split(','): tempstring = '* ' if externsyncattrib == 'true': if self.paramIsArray(param): tempstring += 'Each element of the ' elif self.paramIsPointer(param): tempstring += 'The object referenced by the ' else: tempstring += 'The ' tempstring += self.makeParameterName(paramname.text) tempstring += ' parameter' else: tempstring += self.makeThreadDereferenceHumanReadable(externsyncattrib) tempstring += ' in ' tempstring += self.makeFLink(protoname) tempstring += '\n' if ' element of ' in tempstring: self.threadsafety['parameterlists'] += tempstring else: self.threadsafety['parameters'] += tempstring # Find and add any "implicit" parameters that are thread unsafe implicitexternsyncparams = cmd.find('implicitexternsyncparams') if implicitexternsyncparams is not None: for elem in implicitexternsyncparams: self.threadsafety['implicit'] += '* ' self.threadsafety['implicit'] += elem.text[0].upper() self.threadsafety['implicit'] += elem.text[1:] self.threadsafety['implicit'] += ' in ' self.threadsafety['implicit'] += self.makeFLink(protoname) self.threadsafety['implicit'] += '\n' # Add a VU for any command requiring host synchronization. # This could be further parameterized, if a future non-Vulkan API # requires it. if self.genOpts.conventions.is_externsync_command(protoname): self.threadsafety['implicit'] += '* ' self.threadsafety['implicit'] += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in ' self.threadsafety['implicit'] += self.makeFLink(protoname) self.threadsafety['implicit'] += '\n' # Command generation def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) # @@@ (Jon) something needs to be done here to handle aliases, probably self.makeThreadSafetyBlocks(cmdinfo.elem, 'param') self.writeInclude()