1#!/usr/bin/python3 -i 2# 3# Copyright 2013-2023 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7from generator import OutputGenerator, write 8import os 9 10queueTypeToQueueFlags = { 11 'graphics' : 'VK_QUEUE_GRAPHICS_BIT', 12 'compute' : 'VK_QUEUE_COMPUTE_BIT', 13 'transfer' : 'VK_QUEUE_TRANSFER_BIT', 14 'sparse_binding' : 'VK_QUEUE_SPARSE_BINDING_BIT', 15 'decode' : 'VK_QUEUE_VIDEO_DECODE_BIT_KHR', 16 'encode' : 'VK_QUEUE_VIDEO_ENCODE_BIT_KHR', 17 'opticalflow' : 'VK_QUEUE_OPTICAL_FLOW_BIT_NV', 18} 19 20class SyncOutputGenerator(OutputGenerator): 21 """SyncOutputGenerator - subclass of OutputGenerator. 22 Generates AsciiDoc includes of the table for the Synchronization chapters 23 of the API specification. 24 25 ---- methods ---- 26 SyncOutputGenerator(errFile, warnFile, diagFile) - args as for 27 OutputGenerator. Defines additional internal state. 28 ---- methods overriding base class ---- 29 """ 30 31 def __init__(self, *args, **kwargs): 32 super().__init__(*args, **kwargs) 33 34 # List of all elements 35 self.pipeline_stages = [] 36 self.access_flags = [] 37 38 # <Pipeline Stage, condition as asciidoc string> 39 self.pipeline_stage_condition = dict() 40 # <sccess flag, condition as asciidoc string> 41 self.access_flag_condition = dict() 42 43 # <Pipeline Stage, [equivalent pipeline stages]> 44 self.pipeline_stage_equivalent = dict() 45 # <Pipeline Stage, [queue support]> 46 self.pipeline_stage_queue_support = dict() 47 48 # <Access Flag, [equivalent access flaga]> 49 self.access_flag_equivalent = dict() 50 # <Access Flag, [pipeline stage support]> 51 self.access_flag_stage_support = dict() 52 53 self.pipeline_order_info = [] 54 55 def endFile(self): 56 self.writeFlagDefinitions() 57 self.supportedPipelineStages() 58 self.supportedAccessTypes() 59 self.pipelineOrdering() 60 OutputGenerator.endFile(self) 61 62 def writeBlock(self, basename, contents): 63 """Generate an include file. 64 65 - directory - subdirectory to put file in 66 - basename - base name of the file 67 - contents - contents of the file (Asciidoc boilerplate aside)""" 68 69 filename = self.genOpts.directory + '/' + basename 70 self.logMsg('diag', '# Generating include file:', filename) 71 dirname = os.path.dirname(filename) 72 if not os.path.exists(dirname): 73 os.makedirs(dirname) 74 with open(filename, 'w', encoding='utf-8') as fp: 75 write(self.genOpts.conventions.warning_comment, file=fp) 76 77 if len(contents) > 0: 78 for str in contents: 79 write(str, file=fp) 80 else: 81 self.logMsg('diag', '# No contents for:', filename) 82 83 def genSyncStage(self, stageinfo): 84 OutputGenerator.genSyncStage(self, stageinfo) 85 name = stageinfo.elem.get('name') 86 self.pipeline_stages.append(name) 87 88 if stageinfo.condition is not None: 89 self.pipeline_stage_condition[name] = stageinfo.condition 90 91 syncsupport = stageinfo.elem.find('syncsupport') 92 if syncsupport is not None: 93 self.pipeline_stage_queue_support[name] = syncsupport.get('queues').split(',') 94 95 syncequivalent = stageinfo.elem.find('syncequivalent') 96 if syncequivalent is not None: 97 self.pipeline_stage_equivalent[name] = syncequivalent.get('stage').split(',') 98 99 def genSyncAccess(self, accessinfo): 100 OutputGenerator.genSyncStage(self, accessinfo) 101 name = accessinfo.elem.get('name') 102 self.access_flags.append(name) 103 104 if accessinfo.condition is not None: 105 self.access_flag_condition[name] = accessinfo.condition 106 107 syncsupport = accessinfo.elem.find('syncsupport') 108 if syncsupport is not None: 109 self.access_flag_stage_support[name] = syncsupport.get('stage').split(',') 110 111 syncequivalent = accessinfo.elem.find('syncequivalent') 112 if syncequivalent is not None: 113 self.access_flag_equivalent[name] = syncequivalent.get('access').split(',') 114 115 def genSyncPipeline(self, pipelineinfo): 116 OutputGenerator.genSyncStage(self, pipelineinfo) 117 self.pipeline_order_info.append(pipelineinfo) 118 119 def isSameConditionPipeline(self, condition, stage): 120 if stage not in self.pipeline_stage_condition: 121 return False 122 if condition is None: 123 return False 124 return self.pipeline_stage_condition[stage] == condition 125 126 def isSameConditionPipelineAccess(self, stage, flag): 127 if stage not in self.pipeline_stage_condition: 128 return False 129 if flag not in self.access_flag_condition: 130 return False 131 return self.pipeline_stage_condition[stage] == self.access_flag_condition[flag] 132 133 def writePipelineIfdef(self, stage, list): 134 condition = self.pipeline_stage_condition[stage] if stage in self.pipeline_stage_condition else None 135 if condition is not None: 136 list.append('ifdef::{}[]'.format(condition)) 137 138 def writePipelineEndif(self, stage, list): 139 condition = self.pipeline_stage_condition[stage] if stage in self.pipeline_stage_condition else None 140 if condition is not None: 141 list.append('endif::{}[]'.format(condition)) 142 143 def writeAccessIfdef(self, flag, list): 144 condition = self.access_flag_condition[flag] if flag in self.access_flag_condition else None 145 if condition is not None: 146 list.append('ifdef::{}[]'.format(condition)) 147 148 def writeAccessEndif(self, flag, list): 149 condition = self.access_flag_condition[flag] if flag in self.access_flag_condition else None 150 if condition is not None: 151 list.append('endif::{}[]'.format(condition)) 152 153 def writeFlagDefinitions(self): 154 for name, stages in self.pipeline_stage_equivalent.items(): 155 output = [] 156 for stage in stages: 157 self.writePipelineIfdef(stage, output) 158 output.append(' ** ename:{}'.format(stage)) 159 self.writePipelineEndif(stage, output) 160 161 self.writeBlock(f'flagDefinitions/{name}{self.file_suffix}', output) 162 163 for name, flags in self.access_flag_equivalent.items(): 164 output = [] 165 for flag in flags: 166 self.writeAccessIfdef(flag, output) 167 output.append(' ** ename:{}'.format(flag)) 168 self.writeAccessEndif(flag, output) 169 170 self.writeBlock(f'flagDefinitions/{name}{self.file_suffix}', output) 171 172 def supportedPipelineStages(self): 173 output = [] 174 for stage in self.pipeline_stages: 175 self.writePipelineIfdef(stage, output) 176 queue_support = '' 177 if stage not in self.pipeline_stage_queue_support: 178 queue_support = 'None required' 179 else: 180 for queue in self.pipeline_stage_queue_support[stage]: 181 ename = 'ename:{}'.format(queueTypeToQueueFlags[queue]) 182 if queue_support != '': 183 queue_support += ' or ' 184 queue_support += ename 185 186 output.append('|ename:{} | {}'.format(stage, queue_support)) 187 188 self.writePipelineEndif(stage, output) 189 190 self.writeBlock(f'supportedPipelineStages{self.file_suffix}', output) 191 192 def supportedAccessTypes(self): 193 output = [] 194 for flag in self.access_flags: 195 self.writeAccessIfdef(flag, output) 196 output.append('|ename:{} |'.format(flag)) 197 198 if flag not in self.access_flag_stage_support: 199 output.append('\tAny') 200 else: 201 stages = self.access_flag_stage_support[flag] 202 for index, stage in enumerate(stages): 203 end_symbol = '' 204 if index != (len(stages) - 1) and len(stages) > 1: 205 end_symbol = ',' 206 207 if not self.isSameConditionPipelineAccess(stage, flag): 208 self.writePipelineIfdef(stage, output) 209 output.append('\tename:{}{}'.format(stage, end_symbol)) 210 if not self.isSameConditionPipelineAccess(stage, flag): 211 self.writePipelineEndif(stage, output) 212 213 self.writeAccessEndif(flag, output) 214 215 self.writeBlock(f'supportedAccessTypes{self.file_suffix}', output) 216 217 def pipelineOrdering(self): 218 for pipelineinfo in self.pipeline_order_info: 219 output = [] 220 name = pipelineinfo.elem.get('name') 221 depends = pipelineinfo.elem.get('depends') 222 syncPipelineStages = pipelineinfo.elem.findall('syncpipelinestage') 223 224 for stageElem in syncPipelineStages: 225 stage = stageElem.text 226 order = stageElem.get('order') 227 before = stageElem.get('before') 228 after = stageElem.get('after') 229 if order == 'None': 230 continue 231 232 if not self.isSameConditionPipeline(depends, stage): 233 self.writePipelineIfdef(stage, output) 234 235 output.append(' * ename:{}'.format(stage)) 236 237 if not self.isSameConditionPipeline(depends, stage): 238 self.writePipelineEndif(stage, output) 239 240 file_name = name.replace(' ', '_') 241 self.writeBlock(f'pipelineOrders/{file_name}{self.file_suffix}', output) 242