#!/usr/bin/python3 -i # # Copyright 2013-2023 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 from generator import OutputGenerator, write import os queueTypeToQueueFlags = { 'graphics' : 'VK_QUEUE_GRAPHICS_BIT', 'compute' : 'VK_QUEUE_COMPUTE_BIT', 'transfer' : 'VK_QUEUE_TRANSFER_BIT', 'sparse_binding' : 'VK_QUEUE_SPARSE_BINDING_BIT', 'decode' : 'VK_QUEUE_VIDEO_DECODE_BIT_KHR', 'encode' : 'VK_QUEUE_VIDEO_ENCODE_BIT_KHR', 'opticalflow' : 'VK_QUEUE_OPTICAL_FLOW_BIT_NV', } class SyncOutputGenerator(OutputGenerator): """SyncOutputGenerator - subclass of OutputGenerator. Generates AsciiDoc includes of the table for the Synchronization chapters of the API specification. ---- methods ---- SyncOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state. ---- methods overriding base class ---- """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # List of all elements self.pipeline_stages = [] self.access_flags = [] # self.pipeline_stage_condition = dict() # self.access_flag_condition = dict() # self.pipeline_stage_equivalent = dict() # self.pipeline_stage_queue_support = dict() # self.access_flag_equivalent = dict() # self.access_flag_stage_support = dict() self.pipeline_order_info = [] def endFile(self): self.writeFlagDefinitions() self.supportedPipelineStages() self.supportedAccessTypes() self.pipelineOrdering() OutputGenerator.endFile(self) def writeBlock(self, basename, contents): """Generate an include file. - directory - subdirectory to put file in - basename - base name of the file - contents - contents of the file (Asciidoc boilerplate aside)""" filename = self.genOpts.directory + '/' + basename self.logMsg('diag', '# Generating include file:', filename) dirname = os.path.dirname(filename) if not os.path.exists(dirname): os.makedirs(dirname) with open(filename, 'w', encoding='utf-8') as fp: write(self.genOpts.conventions.warning_comment, file=fp) if len(contents) > 0: for str in contents: write(str, file=fp) else: self.logMsg('diag', '# No contents for:', filename) def genSyncStage(self, stageinfo): OutputGenerator.genSyncStage(self, stageinfo) name = stageinfo.elem.get('name') self.pipeline_stages.append(name) if stageinfo.condition is not None: self.pipeline_stage_condition[name] = stageinfo.condition syncsupport = stageinfo.elem.find('syncsupport') if syncsupport is not None: self.pipeline_stage_queue_support[name] = syncsupport.get('queues').split(',') syncequivalent = stageinfo.elem.find('syncequivalent') if syncequivalent is not None: self.pipeline_stage_equivalent[name] = syncequivalent.get('stage').split(',') def genSyncAccess(self, accessinfo): OutputGenerator.genSyncStage(self, accessinfo) name = accessinfo.elem.get('name') self.access_flags.append(name) if accessinfo.condition is not None: self.access_flag_condition[name] = accessinfo.condition syncsupport = accessinfo.elem.find('syncsupport') if syncsupport is not None: self.access_flag_stage_support[name] = syncsupport.get('stage').split(',') syncequivalent = accessinfo.elem.find('syncequivalent') if syncequivalent is not None: self.access_flag_equivalent[name] = syncequivalent.get('access').split(',') def genSyncPipeline(self, pipelineinfo): OutputGenerator.genSyncStage(self, pipelineinfo) self.pipeline_order_info.append(pipelineinfo) def isSameConditionPipeline(self, condition, stage): if stage not in self.pipeline_stage_condition: return False if condition is None: return False return self.pipeline_stage_condition[stage] == condition def isSameConditionPipelineAccess(self, stage, flag): if stage not in self.pipeline_stage_condition: return False if flag not in self.access_flag_condition: return False return self.pipeline_stage_condition[stage] == self.access_flag_condition[flag] def writePipelineIfdef(self, stage, list): condition = self.pipeline_stage_condition[stage] if stage in self.pipeline_stage_condition else None if condition is not None: list.append('ifdef::{}[]'.format(condition)) def writePipelineEndif(self, stage, list): condition = self.pipeline_stage_condition[stage] if stage in self.pipeline_stage_condition else None if condition is not None: list.append('endif::{}[]'.format(condition)) def writeAccessIfdef(self, flag, list): condition = self.access_flag_condition[flag] if flag in self.access_flag_condition else None if condition is not None: list.append('ifdef::{}[]'.format(condition)) def writeAccessEndif(self, flag, list): condition = self.access_flag_condition[flag] if flag in self.access_flag_condition else None if condition is not None: list.append('endif::{}[]'.format(condition)) def writeFlagDefinitions(self): for name, stages in self.pipeline_stage_equivalent.items(): output = [] for stage in stages: self.writePipelineIfdef(stage, output) output.append(' ** ename:{}'.format(stage)) self.writePipelineEndif(stage, output) self.writeBlock(f'flagDefinitions/{name}{self.file_suffix}', output) for name, flags in self.access_flag_equivalent.items(): output = [] for flag in flags: self.writeAccessIfdef(flag, output) output.append(' ** ename:{}'.format(flag)) self.writeAccessEndif(flag, output) self.writeBlock(f'flagDefinitions/{name}{self.file_suffix}', output) def supportedPipelineStages(self): output = [] for stage in self.pipeline_stages: self.writePipelineIfdef(stage, output) queue_support = '' if stage not in self.pipeline_stage_queue_support: queue_support = 'None required' else: for queue in self.pipeline_stage_queue_support[stage]: ename = 'ename:{}'.format(queueTypeToQueueFlags[queue]) if queue_support != '': queue_support += ' or ' queue_support += ename output.append('|ename:{} | {}'.format(stage, queue_support)) self.writePipelineEndif(stage, output) self.writeBlock(f'supportedPipelineStages{self.file_suffix}', output) def supportedAccessTypes(self): output = [] for flag in self.access_flags: self.writeAccessIfdef(flag, output) output.append('|ename:{} |'.format(flag)) if flag not in self.access_flag_stage_support: output.append('\tAny') else: stages = self.access_flag_stage_support[flag] for index, stage in enumerate(stages): end_symbol = '' if index != (len(stages) - 1) and len(stages) > 1: end_symbol = ',' if not self.isSameConditionPipelineAccess(stage, flag): self.writePipelineIfdef(stage, output) output.append('\tename:{}{}'.format(stage, end_symbol)) if not self.isSameConditionPipelineAccess(stage, flag): self.writePipelineEndif(stage, output) self.writeAccessEndif(flag, output) self.writeBlock(f'supportedAccessTypes{self.file_suffix}', output) def pipelineOrdering(self): for pipelineinfo in self.pipeline_order_info: output = [] name = pipelineinfo.elem.get('name') depends = pipelineinfo.elem.get('depends') syncPipelineStages = pipelineinfo.elem.findall('syncpipelinestage') for stageElem in syncPipelineStages: stage = stageElem.text order = stageElem.get('order') before = stageElem.get('before') after = stageElem.get('after') if order == 'None': continue if not self.isSameConditionPipeline(depends, stage): self.writePipelineIfdef(stage, output) output.append(' * ename:{}'.format(stage)) if not self.isSameConditionPipeline(depends, stage): self.writePipelineEndif(stage, output) file_name = name.replace(' ', '_') self.writeBlock(f'pipelineOrders/{file_name}{self.file_suffix}', output)