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_cifrom spec_tools.attributes import ExternSyncEntry
9e5c31af7Sopenharmony_cifrom spec_tools.validity import ValidityCollection, ValidityEntry
10e5c31af7Sopenharmony_cifrom spec_tools.util import getElemName
11e5c31af7Sopenharmony_ci
12e5c31af7Sopenharmony_ci
13e5c31af7Sopenharmony_ciclass HostSynchronizationOutputGenerator(OutputGenerator):
14e5c31af7Sopenharmony_ci    """HostSynchronizationOutputGenerator - subclass of OutputGenerator.
15e5c31af7Sopenharmony_ci    Generates AsciiDoc includes of the externsync parameter table for the
16e5c31af7Sopenharmony_ci    fundamentals chapter of the API specification. Similar to
17e5c31af7Sopenharmony_ci    DocOutputGenerator.
18e5c31af7Sopenharmony_ci
19e5c31af7Sopenharmony_ci    ---- methods ----
20e5c31af7Sopenharmony_ci    HostSynchronizationOutputGenerator(errFile, warnFile, diagFile) - args as for
21e5c31af7Sopenharmony_ci      OutputGenerator. Defines additional internal state.
22e5c31af7Sopenharmony_ci    ---- methods overriding base class ----
23e5c31af7Sopenharmony_ci    genCmd(cmdinfo)"""
24e5c31af7Sopenharmony_ci    # Generate Host Synchronized Parameters in a table at the top of the spec
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci    threadsafety = {
27e5c31af7Sopenharmony_ci        'parameters': ValidityCollection(),
28e5c31af7Sopenharmony_ci        'parameterlists': ValidityCollection(),
29e5c31af7Sopenharmony_ci        'implicit': ValidityCollection()
30e5c31af7Sopenharmony_ci    }
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_ci    def makeParameterName(self, name):
33e5c31af7Sopenharmony_ci        return 'pname:' + name
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_ci    def makeFLink(self, name):
36e5c31af7Sopenharmony_ci        return 'flink:' + name
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ci    def writeBlock(self, basename, title, contents):
39e5c31af7Sopenharmony_ci        """Generate an include file.
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ci        - directory - subdirectory to put file in
42e5c31af7Sopenharmony_ci        - basename - base name of the file
43e5c31af7Sopenharmony_ci        - contents - contents of the file (Asciidoc boilerplate aside)"""
44e5c31af7Sopenharmony_ci        filename = self.genOpts.directory + '/' + basename
45e5c31af7Sopenharmony_ci        self.logMsg('diag', '# Generating include file:', filename)
46e5c31af7Sopenharmony_ci        with open(filename, 'w', encoding='utf-8') as fp:
47e5c31af7Sopenharmony_ci            write(self.genOpts.conventions.warning_comment, file=fp)
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_ci            if contents:
50e5c31af7Sopenharmony_ci                write('.%s' % title, file=fp)
51e5c31af7Sopenharmony_ci                write('****', file=fp)
52e5c31af7Sopenharmony_ci                write(contents, file=fp, end='')
53e5c31af7Sopenharmony_ci                write('****', file=fp)
54e5c31af7Sopenharmony_ci                write('', file=fp)
55e5c31af7Sopenharmony_ci            else:
56e5c31af7Sopenharmony_ci                self.logMsg('diag', '# No contents for:', filename)
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_ci    def writeInclude(self):
59e5c31af7Sopenharmony_ci        "Generates the asciidoc include files."""
60e5c31af7Sopenharmony_ci        self.writeBlock('parameters.adoc',
61e5c31af7Sopenharmony_ci                        'Externally Synchronized Parameters',
62e5c31af7Sopenharmony_ci                        self.threadsafety['parameters'])
63e5c31af7Sopenharmony_ci        self.writeBlock('parameterlists.adoc',
64e5c31af7Sopenharmony_ci                        'Externally Synchronized Parameter Lists',
65e5c31af7Sopenharmony_ci                        self.threadsafety['parameterlists'])
66e5c31af7Sopenharmony_ci        self.writeBlock('implicit.adoc',
67e5c31af7Sopenharmony_ci                        'Implicit Externally Synchronized Parameters',
68e5c31af7Sopenharmony_ci                        self.threadsafety['implicit'])
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_ci    def makeThreadSafetyBlocks(self, cmd, paramtext):
71e5c31af7Sopenharmony_ci        # See also makeThreadSafetyBlock in validitygenerator.py - similar but not entirely identical
72e5c31af7Sopenharmony_ci        protoname = cmd.find('proto/name').text
73e5c31af7Sopenharmony_ci
74e5c31af7Sopenharmony_ci        # Find and add any parameters that are thread unsafe
75e5c31af7Sopenharmony_ci        explicitexternsyncparams = cmd.findall(paramtext + "[@externsync]")
76e5c31af7Sopenharmony_ci        if explicitexternsyncparams is not None:
77e5c31af7Sopenharmony_ci            for param in explicitexternsyncparams:
78e5c31af7Sopenharmony_ci                self.makeThreadSafetyForParam(protoname, param)
79e5c31af7Sopenharmony_ci
80e5c31af7Sopenharmony_ci        # Find and add any "implicit" parameters that are thread unsafe
81e5c31af7Sopenharmony_ci        implicitexternsyncparams = cmd.find('implicitexternsyncparams')
82e5c31af7Sopenharmony_ci        if implicitexternsyncparams is not None:
83e5c31af7Sopenharmony_ci            for elem in implicitexternsyncparams:
84e5c31af7Sopenharmony_ci                entry = ValidityEntry()
85e5c31af7Sopenharmony_ci                entry += elem.text
86e5c31af7Sopenharmony_ci                entry += ' in '
87e5c31af7Sopenharmony_ci                entry += self.makeFLink(protoname)
88e5c31af7Sopenharmony_ci                self.threadsafety['implicit'] += entry
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci        # Add a VU for any command requiring host synchronization.
91e5c31af7Sopenharmony_ci        # This could be further parameterized, if a future non-Vulkan API
92e5c31af7Sopenharmony_ci        # requires it.
93e5c31af7Sopenharmony_ci        if self.genOpts.conventions.is_externsync_command(protoname):
94e5c31af7Sopenharmony_ci            entry = ValidityEntry()
95e5c31af7Sopenharmony_ci            entry += 'The sname:VkCommandPool that pname:commandBuffer was allocated from, in '
96e5c31af7Sopenharmony_ci            entry += self.makeFLink(protoname)
97e5c31af7Sopenharmony_ci            self.threadsafety['implicit'] += entry
98e5c31af7Sopenharmony_ci
99e5c31af7Sopenharmony_ci    def makeThreadSafetyForParam(self, protoname, param):
100e5c31af7Sopenharmony_ci        """Create thread safety validity for a single param of a command."""
101e5c31af7Sopenharmony_ci        externsyncattribs = ExternSyncEntry.parse_externsync_from_param(param)
102e5c31af7Sopenharmony_ci        param_name = getElemName(param)
103e5c31af7Sopenharmony_ci
104e5c31af7Sopenharmony_ci        for attrib in externsyncattribs:
105e5c31af7Sopenharmony_ci            entry = ValidityEntry()
106e5c31af7Sopenharmony_ci            is_array = False
107e5c31af7Sopenharmony_ci            if attrib.entirely_extern_sync:
108e5c31af7Sopenharmony_ci                # "true" or "true_with_children"
109e5c31af7Sopenharmony_ci                if self.paramIsArray(param):
110e5c31af7Sopenharmony_ci                    entry += 'Each element of the '
111e5c31af7Sopenharmony_ci                    is_array = True
112e5c31af7Sopenharmony_ci                elif self.paramIsPointer(param):
113e5c31af7Sopenharmony_ci                    entry += 'The object referenced by the '
114e5c31af7Sopenharmony_ci                else:
115e5c31af7Sopenharmony_ci                    entry += 'The '
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ci                entry += self.makeParameterName(param_name)
118e5c31af7Sopenharmony_ci                entry += ' parameter'
119e5c31af7Sopenharmony_ci
120e5c31af7Sopenharmony_ci                if attrib.children_extern_sync:
121e5c31af7Sopenharmony_ci                    entry += ', and any child handles,'
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ci            else:
124e5c31af7Sopenharmony_ci                # parameter/member reference
125e5c31af7Sopenharmony_ci                readable = attrib.get_human_readable(make_param_name=self.makeParameterName)
126e5c31af7Sopenharmony_ci                is_array = (' element of ' in readable)
127e5c31af7Sopenharmony_ci                entry += readable
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci            entry += ' in '
130e5c31af7Sopenharmony_ci            entry += self.makeFLink(protoname)
131e5c31af7Sopenharmony_ci
132e5c31af7Sopenharmony_ci            if is_array:
133e5c31af7Sopenharmony_ci                self.threadsafety['parameterlists'] += entry
134e5c31af7Sopenharmony_ci            else:
135e5c31af7Sopenharmony_ci                self.threadsafety['parameters'] += entry
136e5c31af7Sopenharmony_ci
137e5c31af7Sopenharmony_ci    def genCmd(self, cmdinfo, name, alias):
138e5c31af7Sopenharmony_ci        "Generate command."
139e5c31af7Sopenharmony_ci        OutputGenerator.genCmd(self, cmdinfo, name, alias)
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_ci        # @@@ (Jon) something needs to be done here to handle aliases, probably
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci        self.makeThreadSafetyBlocks(cmdinfo.elem, 'param')
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_ci        self.writeInclude()
146