| #!/usr/bin/python3 -i |
| # |
| # Copyright (c) 2013-2018 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 os,re,sys |
| from generator import * |
| |
| # HostSynchronizationOutputGenerator - subclass of OutputGenerator. |
| # Generates AsciiDoc includes of the externsync parameter table for the |
| # fundamentals chapter of the Vulkan 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('// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry', 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('// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry', 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('// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry', 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.attrib.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.attrib.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' |
| |
| |
| # For any vkCmd* functions, the command pool is externally synchronized |
| if protoname is not None and 'vkCmd' in 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() |