/ scripts / hostsyncgenerator.py
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()