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