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