1#!/usr/bin/python3
2# Copyright 2019 The ANGLE Project Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5#
6# gen_mtl_internal_shaders.py:
7#   Code generation for Metal backend's default shaders.
8#   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
9
10import json
11import os
12import subprocess
13import sys
14
15sys.path.append('../..')
16import angle_format
17import gen_angle_format_table
18
19template_header_boilerplate = """// GENERATED FILE - DO NOT EDIT.
20// Generated by {script_name}
21//
22// Copyright 2020 The ANGLE Project Authors. All rights reserved.
23// Use of this source code is governed by a BSD-style license that can be
24// found in the LICENSE file.
25//
26"""
27
28def gen_shader_enums_code(angle_formats):
29
30    code = """// This file is similar to src/libANGLE/renderer/FormatID_autogen.h but is used by Metal default
31// shaders instead of C++ code.
32//
33"""
34
35    code += "namespace rx\n"
36    code += "{\n"
37    code += "namespace mtl_shader\n"
38    code += "{\n"
39    code += "\n"
40    code += "namespace FormatID\n"
41    code += "{\n"
42    code += "enum\n"
43    code += "{\n"
44    code += gen_angle_format_table.gen_enum_string(angle_formats) + '\n'
45    code += "};\n\n"
46    code += "}\n"
47    code += "\n"
48    code += "}\n"
49    code += "}\n"
50
51    return code
52
53
54def find_clang():
55    if os.name == 'nt':
56        binary = 'clang-cl.exe'
57    else:
58        binary = 'clang++'
59
60    clang = os.path.join('..', '..', '..', '..', '..', 'third_party', 'llvm-build',
61                         'Release+Asserts', 'bin', binary)
62
63    if not os.path.isfile(clang):
64        raise Exception('Cannot find clang')
65
66    return clang
67
68
69def main():
70    angle_format_script_files = [
71        '../../angle_format_map.json', '../../angle_format.py', '../../gen_angle_format_table.py'
72    ]
73    src_files = [
74        'blit.metal', 'clear.metal', 'gen_indices.metal', 'gen_mipmap.metal', 'copy_buffer.metal',
75        'visibility.metal'
76    ]
77
78    # auto_script parameters.
79    if len(sys.argv) > 1:
80        inputs = angle_format_script_files + src_files + ['common.h', 'constants.h']
81        outputs = ['format_autogen.h', 'mtl_default_shaders_src_autogen.inc']
82
83        if sys.argv[1] == 'inputs':
84            print(','.join(inputs))
85        elif sys.argv[1] == 'outputs':
86            print(','.join(outputs))
87        else:
88            print('Invalid script parameters')
89            return 1
90        return 0
91
92    os.chdir(sys.path[0])
93
94    boilerplate_code = template_header_boilerplate.format(script_name=sys.argv[0])
95
96    # -------- Generate shader constants -----------
97    angle_to_gl = angle_format.load_inverse_table('../../angle_format_map.json')
98    shader_formats_autogen = gen_shader_enums_code(angle_to_gl.keys())
99    shader_autogen_header = boilerplate_code + shader_formats_autogen
100
101    with open('format_autogen.h', 'wt') as out_file:
102        out_file.write(shader_autogen_header)
103        out_file.close()
104
105    # -------- Combine and create shader source string -----------
106    # Generate combined source
107    clang = find_clang()
108
109    # Use clang to preprocess the combination source. "@@" token is used to prevent clang from
110    # expanding the preprocessor directive
111    temp_fname = 'temp_master_source.metal'
112    with open(temp_fname, 'wb') as temp_file:
113        for src_file in src_files:
114            include_str = '#include "' + src_file + '" \n'
115            temp_file.write(include_str.encode('utf-8'))
116
117    args = [clang]
118    if not os.name == 'nt':
119        args += ['-xc++']
120    args += ['-E', temp_fname]
121
122    combined_source = subprocess.check_output(args)
123
124    # Remove '@@' tokens
125    final_combined_src_string = combined_source.replace('@@'.encode('utf-8'), ''.encode('utf-8'))
126
127    # Generate final file:
128    with open('mtl_default_shaders_src_autogen.inc', 'wt') as out_file:
129        out_file.write(boilerplate_code)
130        out_file.write('\n')
131        out_file.write('// C++ string version of combined Metal default shaders.\n\n')
132        out_file.write('\n\nstatic char gDefaultMetallibSrc[] = R"(\n')
133        out_file.write(final_combined_src_string.decode("utf-8"))
134        out_file.write('\n')
135        out_file.write(')";\n')
136        out_file.close()
137
138    os.remove(temp_fname)
139
140
141if __name__ == '__main__':
142    sys.exit(main())
143