blob: d8f282154e1220d5fcd1ba3acb025b5ce0d7a863 [file] [log] [blame]
#!/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 = []
# <Pipeline Stage, condition as asciidoc string>
self.pipeline_stage_condition = dict()
# <sccess flag, condition as asciidoc string>
self.access_flag_condition = dict()
# <Pipeline Stage, [equivalent pipeline stages]>
self.pipeline_stage_equivalent = dict()
# <Pipeline Stage, [queue support]>
self.pipeline_stage_queue_support = dict()
# <Access Flag, [equivalent access flaga]>
self.access_flag_equivalent = dict()
# <Access Flag, [pipeline stage support]>
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)