• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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