xref: /aosp_15_r20/external/mesa3d/src/util/glsl2spirv.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker# Copyright © 2022 Intel Corporation
2*61046927SAndroid Build Coastguard Worker#
3*61046927SAndroid Build Coastguard Worker# Permission is hereby granted, free of charge, to any person obtaining a
4*61046927SAndroid Build Coastguard Worker# copy of this software and associated documentation files (the "Software"),
5*61046927SAndroid Build Coastguard Worker# to deal in the Software without restriction, including without limitation
6*61046927SAndroid Build Coastguard Worker# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7*61046927SAndroid Build Coastguard Worker# and/or sell copies of the Software, and to permit persons to whom the
8*61046927SAndroid Build Coastguard Worker# Software is furnished to do so, subject to the following conditions:
9*61046927SAndroid Build Coastguard Worker#
10*61046927SAndroid Build Coastguard Worker# The above copyright notice and this permission notice (including the next
11*61046927SAndroid Build Coastguard Worker# paragraph) shall be included in all copies or substantial portions of the
12*61046927SAndroid Build Coastguard Worker# Software.
13*61046927SAndroid Build Coastguard Worker#
14*61046927SAndroid Build Coastguard Worker# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*61046927SAndroid Build Coastguard Worker# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*61046927SAndroid Build Coastguard Worker# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*61046927SAndroid Build Coastguard Worker# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*61046927SAndroid Build Coastguard Worker# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19*61046927SAndroid Build Coastguard Worker# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20*61046927SAndroid Build Coastguard Worker# IN THE SOFTWARE.
21*61046927SAndroid Build Coastguard Worker
22*61046927SAndroid Build Coastguard Worker# Converts GLSL shader to SPIR-V library
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Workerimport argparse
25*61046927SAndroid Build Coastguard Workerimport subprocess
26*61046927SAndroid Build Coastguard Workerimport sys
27*61046927SAndroid Build Coastguard Workerimport os
28*61046927SAndroid Build Coastguard Workerimport typing as T
29*61046927SAndroid Build Coastguard Worker
30*61046927SAndroid Build Coastguard Workerif T.TYPE_CHECKING:
31*61046927SAndroid Build Coastguard Worker    class Arguments(T.Protocol):
32*61046927SAndroid Build Coastguard Worker        input: str
33*61046927SAndroid Build Coastguard Worker        output: str
34*61046927SAndroid Build Coastguard Worker        glslang: str
35*61046927SAndroid Build Coastguard Worker        create_entry: T.Optional[str]
36*61046927SAndroid Build Coastguard Worker        glsl_ver: T.Optional[str]
37*61046927SAndroid Build Coastguard Worker        Olib: bool
38*61046927SAndroid Build Coastguard Worker        extra: T.Optional[str]
39*61046927SAndroid Build Coastguard Worker        vn: str
40*61046927SAndroid Build Coastguard Worker        stage: str
41*61046927SAndroid Build Coastguard Worker        includes: T.List[str]
42*61046927SAndroid Build Coastguard Worker        defines: T.List[str]
43*61046927SAndroid Build Coastguard Worker        depfile: T.Optional[str]
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker
46*61046927SAndroid Build Coastguard Workerdef get_args() -> 'Arguments':
47*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
48*61046927SAndroid Build Coastguard Worker    parser.add_argument('input', help="Name of input file.")
49*61046927SAndroid Build Coastguard Worker    parser.add_argument('output', help="Name of output file.")
50*61046927SAndroid Build Coastguard Worker    parser.add_argument('glslang', help="path to glslangValidator")
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker    parser.add_argument("--create-entry",
53*61046927SAndroid Build Coastguard Worker                        dest="create_entry",
54*61046927SAndroid Build Coastguard Worker                        help="Create a new entry point and put to the end of a file.")
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker    parser.add_argument('--glsl-version',
57*61046927SAndroid Build Coastguard Worker                        dest="glsl_ver",
58*61046927SAndroid Build Coastguard Worker                        choices=['100', '110', '120', '130', '140', '150', '300es', '310es', '330', '400', '410', '420', '430', '440', '450', '460'],
59*61046927SAndroid Build Coastguard Worker                        help="Override GLSL #version declaration in source.")
60*61046927SAndroid Build Coastguard Worker
61*61046927SAndroid Build Coastguard Worker    parser.add_argument("-Olib",
62*61046927SAndroid Build Coastguard Worker                        action='store_true',
63*61046927SAndroid Build Coastguard Worker                        help="Any optimizations are disabled and unused functions are saved.")
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker    parser.add_argument("--extra-flags",
66*61046927SAndroid Build Coastguard Worker                        dest="extra",
67*61046927SAndroid Build Coastguard Worker                        help="Pass additional flags to glslangValidator.")
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker    parser.add_argument("--vn",
70*61046927SAndroid Build Coastguard Worker                        dest="vn",
71*61046927SAndroid Build Coastguard Worker                        required=True,
72*61046927SAndroid Build Coastguard Worker                        help="Variable name. Creates a C header file that contains a uint32_t array.")
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker    parser.add_argument("--stage",
75*61046927SAndroid Build Coastguard Worker                        default="vert",
76*61046927SAndroid Build Coastguard Worker                        choices=['vert', 'tesc', 'tese', 'geom', 'frag', 'comp'],
77*61046927SAndroid Build Coastguard Worker                        help="Uses specified stage rather than parsing the file extension")
78*61046927SAndroid Build Coastguard Worker
79*61046927SAndroid Build Coastguard Worker    parser.add_argument("-I",
80*61046927SAndroid Build Coastguard Worker                        dest="includes",
81*61046927SAndroid Build Coastguard Worker                        default=[],
82*61046927SAndroid Build Coastguard Worker                        action='append',
83*61046927SAndroid Build Coastguard Worker                        help="Include directory")
84*61046927SAndroid Build Coastguard Worker
85*61046927SAndroid Build Coastguard Worker    parser.add_argument("-D",
86*61046927SAndroid Build Coastguard Worker                        dest="defines",
87*61046927SAndroid Build Coastguard Worker                        default=[],
88*61046927SAndroid Build Coastguard Worker                        action='append',
89*61046927SAndroid Build Coastguard Worker                        help="Defines")
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker    parser.add_argument('--depfile',
92*61046927SAndroid Build Coastguard Worker                        dest="depfile",
93*61046927SAndroid Build Coastguard Worker                        default=None,
94*61046927SAndroid Build Coastguard Worker                        action='store',
95*61046927SAndroid Build Coastguard Worker                        help='Where glslangValidator should write its depfile, if unset no depfile will be written.')
96*61046927SAndroid Build Coastguard Worker
97*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
98*61046927SAndroid Build Coastguard Worker    return args
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Workerdef create_include_guard(lines: T.List[str], filename: str) -> T.List[str]:
102*61046927SAndroid Build Coastguard Worker    filename = filename.replace('.', '_')
103*61046927SAndroid Build Coastguard Worker    upper_name = filename.upper()
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker    guard_head = [f"#ifndef {upper_name}\n",
106*61046927SAndroid Build Coastguard Worker                  f"#define {upper_name}\n"]
107*61046927SAndroid Build Coastguard Worker    guard_tail = [f"\n#endif // {upper_name}\n"]
108*61046927SAndroid Build Coastguard Worker
109*61046927SAndroid Build Coastguard Worker    # remove '#pragma once'
110*61046927SAndroid Build Coastguard Worker    for idx, l in enumerate(lines):
111*61046927SAndroid Build Coastguard Worker        if '#pragma once' in l:
112*61046927SAndroid Build Coastguard Worker            lines.pop(idx)
113*61046927SAndroid Build Coastguard Worker            break
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Worker    return guard_head + lines + guard_tail
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Workerdef convert_to_static_variable(lines: T.List[str], varname: str) -> T.List[str]:
119*61046927SAndroid Build Coastguard Worker    for idx, l in enumerate(lines):
120*61046927SAndroid Build Coastguard Worker        if varname in l:
121*61046927SAndroid Build Coastguard Worker            lines[idx] = f"static {l}"
122*61046927SAndroid Build Coastguard Worker            return lines
123*61046927SAndroid Build Coastguard Worker    raise RuntimeError(f'Did not find {varname}, this is unexpected')
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Workerdef override_version(lines: T.List[str], glsl_version: str) -> T.List[str]:
127*61046927SAndroid Build Coastguard Worker    for idx, l in enumerate(lines):
128*61046927SAndroid Build Coastguard Worker        if '#version ' in l:
129*61046927SAndroid Build Coastguard Worker            lines[idx] = f"#version {glsl_version}\n"
130*61046927SAndroid Build Coastguard Worker            return lines
131*61046927SAndroid Build Coastguard Worker    raise RuntimeError('Did not find #version directive, this is unexpected')
132*61046927SAndroid Build Coastguard Worker
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Workerdef postprocess_file(args: 'Arguments') -> None:
135*61046927SAndroid Build Coastguard Worker    with open(args.output, "r") as r:
136*61046927SAndroid Build Coastguard Worker        lines = r.readlines()
137*61046927SAndroid Build Coastguard Worker
138*61046927SAndroid Build Coastguard Worker    # glslangValidator creates a variable without the static modifier.
139*61046927SAndroid Build Coastguard Worker    lines = convert_to_static_variable(lines, args.vn)
140*61046927SAndroid Build Coastguard Worker
141*61046927SAndroid Build Coastguard Worker    # '#pragma once' is unstandardised.
142*61046927SAndroid Build Coastguard Worker    lines = create_include_guard(lines, os.path.basename(r.name))
143*61046927SAndroid Build Coastguard Worker
144*61046927SAndroid Build Coastguard Worker    with open(args.output, "w") as w:
145*61046927SAndroid Build Coastguard Worker        w.writelines(lines)
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker
148*61046927SAndroid Build Coastguard Workerdef preprocess_file(args: 'Arguments', origin_file: T.TextIO, directory: os.PathLike, filemap: T.Dict[str, str]) -> str:
149*61046927SAndroid Build Coastguard Worker    if args.create_entry is None and args.glsl_ver is None:
150*61046927SAndroid Build Coastguard Worker        return origin_file.name
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker    with open(os.path.join(directory, os.path.basename(origin_file.name)), "w") as copy_file:
153*61046927SAndroid Build Coastguard Worker        lines = origin_file.readlines()
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker        if args.create_entry is not None:
156*61046927SAndroid Build Coastguard Worker            lines.append(f"\nvoid {args.create_entry}() {{}}\n")
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker        if args.glsl_ver is not None:
159*61046927SAndroid Build Coastguard Worker            override_version(lines, args.glsl_ver)
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker        copy_file.writelines(lines)
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker    filemap[copy_file.name] = origin_file.name
164*61046927SAndroid Build Coastguard Worker    return copy_file.name
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker
167*61046927SAndroid Build Coastguard Workerdef fixup_depfile(depfile: str, filemap: T.Mapping[str, str]) -> None:
168*61046927SAndroid Build Coastguard Worker    """Replace generated file references in the depfile with their source.
169*61046927SAndroid Build Coastguard Worker    """
170*61046927SAndroid Build Coastguard Worker    depends: T.List[str] = []
171*61046927SAndroid Build Coastguard Worker    out: T.Optional[str] = None
172*61046927SAndroid Build Coastguard Worker    with open(depfile, 'r') as f:
173*61046927SAndroid Build Coastguard Worker        for line in f.readlines():
174*61046927SAndroid Build Coastguard Worker            if ':' in line:
175*61046927SAndroid Build Coastguard Worker                out, line = line.split(':', 1)
176*61046927SAndroid Build Coastguard Worker            depends.extend(l.strip() for l in line.split())
177*61046927SAndroid Build Coastguard Worker
178*61046927SAndroid Build Coastguard Worker    with open(depfile, 'w') as f:
179*61046927SAndroid Build Coastguard Worker        f.write(out)
180*61046927SAndroid Build Coastguard Worker        f.write(': ')
181*61046927SAndroid Build Coastguard Worker        for dep in depends:
182*61046927SAndroid Build Coastguard Worker            f.write(filemap.get(dep, dep))
183*61046927SAndroid Build Coastguard Worker            f.write(' ')
184*61046927SAndroid Build Coastguard Worker        f.write('\n')
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker
187*61046927SAndroid Build Coastguard Workerdef process_file(args: 'Arguments') -> None:
188*61046927SAndroid Build Coastguard Worker    filemap: T.Dict[str, str] = {}
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker    with open(args.input, "r") as infile:
191*61046927SAndroid Build Coastguard Worker        copy_file = preprocess_file(
192*61046927SAndroid Build Coastguard Worker            args, infile, os.path.dirname(args.output), filemap)
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker    cmd_list = [args.glslang]
195*61046927SAndroid Build Coastguard Worker
196*61046927SAndroid Build Coastguard Worker    if args.Olib:
197*61046927SAndroid Build Coastguard Worker        cmd_list.append("--keep-uncalled")
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker    if args.vn is not None:
200*61046927SAndroid Build Coastguard Worker        cmd_list.extend(["--variable-name", args.vn])
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker    if args.extra is not None:
203*61046927SAndroid Build Coastguard Worker        cmd_list.append(args.extra)
204*61046927SAndroid Build Coastguard Worker
205*61046927SAndroid Build Coastguard Worker    if args.create_entry is not None:
206*61046927SAndroid Build Coastguard Worker        cmd_list.extend(["--entry-point", args.create_entry])
207*61046927SAndroid Build Coastguard Worker
208*61046927SAndroid Build Coastguard Worker    if args.depfile is not None:
209*61046927SAndroid Build Coastguard Worker        cmd_list.extend(['--depfile', args.depfile])
210*61046927SAndroid Build Coastguard Worker
211*61046927SAndroid Build Coastguard Worker    for f in args.includes:
212*61046927SAndroid Build Coastguard Worker        cmd_list.append('-I' + f)
213*61046927SAndroid Build Coastguard Worker    for d in args.defines:
214*61046927SAndroid Build Coastguard Worker        cmd_list.append('-D' + d)
215*61046927SAndroid Build Coastguard Worker
216*61046927SAndroid Build Coastguard Worker    cmd_list.extend([
217*61046927SAndroid Build Coastguard Worker        '-V',
218*61046927SAndroid Build Coastguard Worker        '-o', args.output,
219*61046927SAndroid Build Coastguard Worker        '-S', args.stage,
220*61046927SAndroid Build Coastguard Worker        copy_file,
221*61046927SAndroid Build Coastguard Worker    ])
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker    ret = subprocess.run(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30)
224*61046927SAndroid Build Coastguard Worker    if ret.returncode != 0:
225*61046927SAndroid Build Coastguard Worker        print(ret.stdout)
226*61046927SAndroid Build Coastguard Worker        print(ret.stderr, file=sys.stderr)
227*61046927SAndroid Build Coastguard Worker        sys.exit(1)
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker    if args.vn is not None:
230*61046927SAndroid Build Coastguard Worker        postprocess_file(args)
231*61046927SAndroid Build Coastguard Worker
232*61046927SAndroid Build Coastguard Worker    if args.create_entry is not None:
233*61046927SAndroid Build Coastguard Worker        os.remove(copy_file)
234*61046927SAndroid Build Coastguard Worker
235*61046927SAndroid Build Coastguard Worker    if args.depfile is not None:
236*61046927SAndroid Build Coastguard Worker        fixup_depfile(args.depfile, filemap)
237*61046927SAndroid Build Coastguard Worker
238*61046927SAndroid Build Coastguard Worker
239*61046927SAndroid Build Coastguard Workerdef main() -> None:
240*61046927SAndroid Build Coastguard Worker    args = get_args()
241*61046927SAndroid Build Coastguard Worker    process_file(args)
242*61046927SAndroid Build Coastguard Worker
243*61046927SAndroid Build Coastguard Worker
244*61046927SAndroid Build Coastguard Workerif __name__ == "__main__":
245*61046927SAndroid Build Coastguard Worker    main()
246