1#!/usr/bin/python3 -i 2# 3# Copyright 2013-2022 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7from generator import OutputGenerator, write 8from spec_tools.attributes import ExternSyncEntry 9from spec_tools.validity import ValidityCollection, ValidityEntry 10from spec_tools.util import getElemName 11 12 13class HostSynchronizationOutputGenerator(OutputGenerator): 14 """HostSynchronizationOutputGenerator - subclass of OutputGenerator. 15 Generates AsciiDoc includes of the externsync parameter table for the 16 fundamentals chapter of the API specification. Similar to 17 DocOutputGenerator. 18 19 ---- methods ---- 20 HostSynchronizationOutputGenerator(errFile, warnFile, diagFile) - args as for 21 OutputGenerator. Defines additional internal state. 22 ---- methods overriding base class ---- 23 genCmd(cmdinfo)""" 24 # Generate Host Synchronized Parameters in a table at the top of the spec 25 26 threadsafety = { 27 'parameters': ValidityCollection(), 28 'parameterlists': ValidityCollection(), 29 'implicit': ValidityCollection() 30 } 31 32 def makeParameterName(self, name): 33 return 'pname:' + name 34 35 def makeFLink(self, name): 36 return 'flink:' + name 37 38 def writeBlock(self, basename, title, contents): 39 """Generate an include file. 40 41 - directory - subdirectory to put file in 42 - basename - base name of the file 43 - contents - contents of the file (Asciidoc boilerplate aside)""" 44 filename = self.genOpts.directory + '/' + basename 45 self.logMsg('diag', '# Generating include file:', filename) 46 with open(filename, 'w', encoding='utf-8') as fp: 47 write(self.genOpts.conventions.warning_comment, file=fp) 48 49 if contents: 50 write('.%s' % title, file=fp) 51 write('****', file=fp) 52 write(contents, file=fp, end='') 53 write('****', file=fp) 54 write('', file=fp) 55 else: 56 self.logMsg('diag', '# No contents for:', filename) 57 58 def writeInclude(self): 59 "Generates the asciidoc include files.""" 60 self.writeBlock('parameters.adoc', 61 'Externally Synchronized Parameters', 62 self.threadsafety['parameters']) 63 self.writeBlock('parameterlists.adoc', 64 'Externally Synchronized Parameter Lists', 65 self.threadsafety['parameterlists']) 66 self.writeBlock('implicit.adoc', 67 'Implicit Externally Synchronized Parameters', 68 self.threadsafety['implicit']) 69 70 def makeThreadSafetyBlocks(self, cmd, paramtext): 71 # See also makeThreadSafetyBlock in validitygenerator.py - similar but not entirely identical 72 protoname = cmd.find('proto/name').text 73 74 # Find and add any parameters that are thread unsafe 75 explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]") 76 if explicitexternsyncparams is not None: 77 for param in explicitexternsyncparams: 78 self.makeThreadSafetyForParam(protoname, param) 79 80 # Find and add any "implicit" parameters that are thread unsafe 81 implicitexternsyncparams = cmd.find('implicitexternsyncparams') 82 if implicitexternsyncparams is not None: 83 for elem in implicitexternsyncparams: 84 entry = ValidityEntry() 85 entry += elem.text 86 entry += ' in ' 87 entry += self.makeFLink(protoname) 88 self.threadsafety['implicit'] += entry 89 90 # Add a VU for any command requiring host synchronization. 91 # This could be further parameterized, if a future non-Vulkan API 92 # requires it. 93 if self.genOpts.conventions.is_externsync_command(protoname): 94 entry = ValidityEntry() 95 entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in ' 96 entry += self.makeFLink(protoname) 97 self.threadsafety['implicit'] += entry 98 99 def makeThreadSafetyForParam(self, protoname, param): 100 """Create thread safety validity for a single param of a command.""" 101 externsyncattribs = ExternSyncEntry.parse_externsync_from_param(param) 102 param_name = getElemName(param) 103 104 for attrib in externsyncattribs: 105 entry = ValidityEntry() 106 is_array = False 107 if attrib.entirely_extern_sync: 108 # "true" or "true_with_children" 109 if self.paramIsArray(param): 110 entry += 'Each element of the ' 111 is_array = True 112 elif self.paramIsPointer(param): 113 entry += 'The object referenced by the ' 114 else: 115 entry += 'The ' 116 117 entry += self.makeParameterName(param_name) 118 entry += ' parameter' 119 120 if attrib.children_extern_sync: 121 entry += ', and any child handles,' 122 123 else: 124 # parameter/member reference 125 readable = attrib.get_human_readable(make_param_name=self.makeParameterName) 126 is_array = (' element of ' in readable) 127 entry += readable 128 129 entry += ' in ' 130 entry += self.makeFLink(protoname) 131 132 if is_array: 133 self.threadsafety['parameterlists'] += entry 134 else: 135 self.threadsafety['parameters'] += entry 136 137 def genCmd(self, cmdinfo, name, alias): 138 "Generate command." 139 OutputGenerator.genCmd(self, cmdinfo, name, alias) 140 141 # @@@ (Jon) something needs to be done here to handle aliases, probably 142 143 self.makeThreadSafetyBlocks(cmdinfo.elem, 'param') 144 145 self.writeInclude() 146