hostsyncgenerator.py
1 #!/usr/bin/python3 -i 2 # 3 # Copyright (c) 2013-2019 The Khronos Group Inc. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 import re 18 import sys 19 20 from generator import OutputGenerator, write 21 22 # HostSynchronizationOutputGenerator - subclass of OutputGenerator. 23 # Generates AsciiDoc includes of the externsync parameter table for the 24 # fundamentals chapter of the API specification. Similar to 25 # DocOutputGenerator. 26 # 27 # ---- methods ---- 28 # HostSynchronizationOutputGenerator(errFile, warnFile, diagFile) - args as for 29 # OutputGenerator. Defines additional internal state. 30 # ---- methods overriding base class ---- 31 # genCmd(cmdinfo) 32 class HostSynchronizationOutputGenerator(OutputGenerator): 33 # Generate Host Synchronized Parameters in a table at the top of the spec 34 def __init__(self, 35 errFile = sys.stderr, 36 warnFile = sys.stderr, 37 diagFile = sys.stdout): 38 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 39 40 threadsafety = {'parameters': '', 'parameterlists': '', 'implicit': ''} 41 42 def makeParameterName(self, name): 43 return 'pname:' + name 44 45 def makeFLink(self, name): 46 return 'flink:' + name 47 48 # Generate an include file 49 # 50 # directory - subdirectory to put file in 51 # basename - base name of the file 52 # contents - contents of the file (Asciidoc boilerplate aside) 53 def writeInclude(self): 54 55 if self.threadsafety['parameters'] is not None: 56 # Create file 57 filename = self.genOpts.directory + '/' + 'parameters.txt' 58 self.logMsg('diag', '# Generating include file:', filename) 59 fp = open(filename, 'w', encoding='utf-8') 60 61 # Host Synchronization 62 write(self.genOpts.conventions.warning_comment, file=fp) 63 write('.Externally Synchronized Parameters', file=fp) 64 write('****', file=fp) 65 write(self.threadsafety['parameters'], file=fp, end='') 66 write('****', file=fp) 67 write('', file=fp) 68 69 if self.threadsafety['parameterlists'] is not None: 70 # Create file 71 filename = self.genOpts.directory + '/' + '/parameterlists.txt' 72 self.logMsg('diag', '# Generating include file:', filename) 73 fp = open(filename, 'w', encoding='utf-8') 74 75 # Host Synchronization 76 write(self.genOpts.conventions.warning_comment, file=fp) 77 write('.Externally Synchronized Parameter Lists', file=fp) 78 write('****', file=fp) 79 write(self.threadsafety['parameterlists'], file=fp, end='') 80 write('****', file=fp) 81 write('', file=fp) 82 83 if self.threadsafety['implicit'] is not None: 84 # Create file 85 filename = self.genOpts.directory + '/' + '/implicit.txt' 86 self.logMsg('diag', '# Generating include file:', filename) 87 fp = open(filename, 'w', encoding='utf-8') 88 89 # Host Synchronization 90 write(self.genOpts.conventions.warning_comment, file=fp) 91 write('.Implicit Externally Synchronized Parameters', file=fp) 92 write('****', file=fp) 93 write(self.threadsafety['implicit'], file=fp, end='') 94 write('****', file=fp) 95 write('', file=fp) 96 97 fp.close() 98 99 # Check if the parameter passed in is a pointer to an array 100 def paramIsArray(self, param): 101 return param.get('len') is not None 102 103 # Check if the parameter passed in is a pointer 104 def paramIsPointer(self, param): 105 ispointer = False 106 paramtype = param.find('type') 107 if paramtype.tail is not None and '*' in paramtype.tail: 108 ispointer = True 109 110 return ispointer 111 112 # Turn the "name[].member[]" notation into plain English. 113 def makeThreadDereferenceHumanReadable(self, dereference): 114 matches = re.findall(r"[\w]+[^\w]*",dereference) 115 stringval = '' 116 for match in reversed(matches): 117 if '->' in match or '.' in match: 118 stringval += 'member of ' 119 if '[]' in match: 120 stringval += 'each element of ' 121 122 stringval += 'the ' 123 stringval += self.makeParameterName(re.findall(r"[\w]+",match)[0]) 124 stringval += ' ' 125 126 stringval += 'parameter' 127 128 return stringval[0].upper() + stringval[1:] 129 130 def makeThreadSafetyBlocks(self, cmd, paramtext): 131 protoname = cmd.find('proto/name').text 132 133 # Find and add any parameters that are thread unsafe 134 explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]") 135 if explicitexternsyncparams is not None: 136 for param in explicitexternsyncparams: 137 externsyncattribs = param.get('externsync') 138 paramname = param.find('name') 139 for externsyncattrib in externsyncattribs.split(','): 140 141 tempstring = '* ' 142 if externsyncattrib == 'true': 143 if self.paramIsArray(param): 144 tempstring += 'Each element of the ' 145 elif self.paramIsPointer(param): 146 tempstring += 'The object referenced by the ' 147 else: 148 tempstring += 'The ' 149 150 tempstring += self.makeParameterName(paramname.text) 151 tempstring += ' parameter' 152 153 else: 154 tempstring += self.makeThreadDereferenceHumanReadable(externsyncattrib) 155 156 tempstring += ' in ' 157 tempstring += self.makeFLink(protoname) 158 tempstring += '\n' 159 160 161 if ' element of ' in tempstring: 162 self.threadsafety['parameterlists'] += tempstring 163 else: 164 self.threadsafety['parameters'] += tempstring 165 166 # Find and add any "implicit" parameters that are thread unsafe 167 implicitexternsyncparams = cmd.find('implicitexternsyncparams') 168 if implicitexternsyncparams is not None: 169 for elem in implicitexternsyncparams: 170 self.threadsafety['implicit'] += '* ' 171 self.threadsafety['implicit'] += elem.text[0].upper() 172 self.threadsafety['implicit'] += elem.text[1:] 173 self.threadsafety['implicit'] += ' in ' 174 self.threadsafety['implicit'] += self.makeFLink(protoname) 175 self.threadsafety['implicit'] += '\n' 176 177 # Add a VU for any command requiring host synchronization. 178 # This could be further parameterized, if a future non-Vulkan API 179 # requires it. 180 if self.genOpts.conventions.is_externsync_command(protoname): 181 self.threadsafety['implicit'] += '* ' 182 self.threadsafety['implicit'] += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in ' 183 self.threadsafety['implicit'] += self.makeFLink(protoname) 184 self.threadsafety['implicit'] += '\n' 185 186 # Command generation 187 def genCmd(self, cmdinfo, name, alias): 188 OutputGenerator.genCmd(self, cmdinfo, name, alias) 189 190 # @@@ (Jon) something needs to be done here to handle aliases, probably 191 192 self.makeThreadSafetyBlocks(cmdinfo.elem, 'param') 193 194 self.writeInclude()