1*8975f5c5SAndroid Build Coastguard Worker#! /usr/bin/python3 2*8975f5c5SAndroid Build Coastguard Worker 3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2022 The ANGLE Project Authors. All rights reserved. 4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 6*8975f5c5SAndroid Build Coastguard Worker# 7*8975f5c5SAndroid Build Coastguard Worker# gen_features.py: 8*8975f5c5SAndroid Build Coastguard Worker# Code generation for ANGLE features. 9*8975f5c5SAndroid Build Coastguard Worker# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 10*8975f5c5SAndroid Build Coastguard Worker 11*8975f5c5SAndroid Build Coastguard Workerfrom collections import namedtuple 12*8975f5c5SAndroid Build Coastguard Workerimport json 13*8975f5c5SAndroid Build Coastguard Workerimport os 14*8975f5c5SAndroid Build Coastguard Workerimport re 15*8975f5c5SAndroid Build Coastguard Workerimport sys 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Workerfeature_files = { 18*8975f5c5SAndroid Build Coastguard Worker 'd3d_features.json': ('D3D', 'FeaturesD3D'), 19*8975f5c5SAndroid Build Coastguard Worker 'frontend_features.json': ('Frontend', 'FrontendFeatures'), 20*8975f5c5SAndroid Build Coastguard Worker 'gl_features.json': ('OpenGL', 'FeaturesGL'), 21*8975f5c5SAndroid Build Coastguard Worker 'mtl_features.json': ('Metal', 'FeaturesMtl'), 22*8975f5c5SAndroid Build Coastguard Worker 'vk_features.json': ('Vulkan', 'FeaturesVk'), 23*8975f5c5SAndroid Build Coastguard Worker} 24*8975f5c5SAndroid Build Coastguard Workerfeature_list_header_file = '../../util/autogen/angle_features_autogen.h' 25*8975f5c5SAndroid Build Coastguard Workerfeature_list_source_file = '../../util/autogen/angle_features_autogen.cpp' 26*8975f5c5SAndroid Build Coastguard Worker 27*8975f5c5SAndroid Build Coastguard Workertemplate_header = u"""// GENERATED FILE - DO NOT EDIT. 28*8975f5c5SAndroid Build Coastguard Worker// Generated by {script_name} using data from {input_file_name}. 29*8975f5c5SAndroid Build Coastguard Worker// 30*8975f5c5SAndroid Build Coastguard Worker{description} 31*8975f5c5SAndroid Build Coastguard Worker 32*8975f5c5SAndroid Build Coastguard Worker#ifndef ANGLE_PLATFORM_AUTOGEN_{NAME}_H_ 33*8975f5c5SAndroid Build Coastguard Worker#define ANGLE_PLATFORM_AUTOGEN_{NAME}_H_ 34*8975f5c5SAndroid Build Coastguard Worker 35*8975f5c5SAndroid Build Coastguard Worker#include "platform/Feature.h" 36*8975f5c5SAndroid Build Coastguard Worker 37*8975f5c5SAndroid Build Coastguard Workernamespace angle 38*8975f5c5SAndroid Build Coastguard Worker{{ 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Workerstruct {name} : FeatureSetBase 41*8975f5c5SAndroid Build Coastguard Worker{{ 42*8975f5c5SAndroid Build Coastguard Worker {name}(); 43*8975f5c5SAndroid Build Coastguard Worker ~{name}(); 44*8975f5c5SAndroid Build Coastguard Worker 45*8975f5c5SAndroid Build Coastguard Worker{features} 46*8975f5c5SAndroid Build Coastguard Worker}}; 47*8975f5c5SAndroid Build Coastguard Worker 48*8975f5c5SAndroid Build Coastguard Workerinline {name}::{name}() = default; 49*8975f5c5SAndroid Build Coastguard Workerinline {name}::~{name}() = default; 50*8975f5c5SAndroid Build Coastguard Worker 51*8975f5c5SAndroid Build Coastguard Worker}} // namespace angle 52*8975f5c5SAndroid Build Coastguard Worker 53*8975f5c5SAndroid Build Coastguard Worker#endif // ANGLE_PLATFORM_AUTOGEN_{NAME}_H_ 54*8975f5c5SAndroid Build Coastguard Worker""" 55*8975f5c5SAndroid Build Coastguard Worker 56*8975f5c5SAndroid Build Coastguard Workertemplate_feature = u""" FeatureInfo {var_name} = {{ 57*8975f5c5SAndroid Build Coastguard Worker "{display_name}", 58*8975f5c5SAndroid Build Coastguard Worker FeatureCategory::{category}, 59*8975f5c5SAndroid Build Coastguard Worker &members, 60*8975f5c5SAndroid Build Coastguard Worker }}; 61*8975f5c5SAndroid Build Coastguard Worker""" 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Workertemplate_feature_list_header = u"""// GENERATED FILE - DO NOT EDIT. 64*8975f5c5SAndroid Build Coastguard Worker// Generated by {script_name} using data from {input_file_name}. 65*8975f5c5SAndroid Build Coastguard Worker// 66*8975f5c5SAndroid Build Coastguard Worker// Copyright 2022 The ANGLE Project Authors. All rights reserved. 67*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be 68*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file. 69*8975f5c5SAndroid Build Coastguard Worker// 70*8975f5c5SAndroid Build Coastguard Worker// angle_features_autogen.h: List of ANGLE features to help enable/disable them in tests. 71*8975f5c5SAndroid Build Coastguard Worker 72*8975f5c5SAndroid Build Coastguard Worker#ifndef ANGLE_SRC_TESTS_TEST_UTIL_AUTOGEN_ANGLE_FEATURES_AUTOGEN_H_ 73*8975f5c5SAndroid Build Coastguard Worker#define ANGLE_SRC_TESTS_TEST_UTIL_AUTOGEN_ANGLE_FEATURES_AUTOGEN_H_ 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker#include "../util_export.h" 76*8975f5c5SAndroid Build Coastguard Worker 77*8975f5c5SAndroid Build Coastguard Workernamespace angle 78*8975f5c5SAndroid Build Coastguard Worker{{ 79*8975f5c5SAndroid Build Coastguard Workerenum class Feature 80*8975f5c5SAndroid Build Coastguard Worker{{ 81*8975f5c5SAndroid Build Coastguard Worker{features} 82*8975f5c5SAndroid Build Coastguard Worker 83*8975f5c5SAndroid Build Coastguard Worker InvalidEnum, 84*8975f5c5SAndroid Build Coastguard Worker EnumCount = InvalidEnum, 85*8975f5c5SAndroid Build Coastguard Worker}}; 86*8975f5c5SAndroid Build Coastguard Worker 87*8975f5c5SAndroid Build Coastguard WorkerANGLE_UTIL_EXPORT extern const char *GetFeatureName(Feature feature); 88*8975f5c5SAndroid Build Coastguard Worker 89*8975f5c5SAndroid Build Coastguard Worker}} // namespace angle 90*8975f5c5SAndroid Build Coastguard Worker 91*8975f5c5SAndroid Build Coastguard Worker#endif // ANGLE_SRC_TESTS_TEST_UTIL_AUTOGEN_ANGLE_FEATURES_AUTOGEN_H_ 92*8975f5c5SAndroid Build Coastguard Worker""" 93*8975f5c5SAndroid Build Coastguard Worker 94*8975f5c5SAndroid Build Coastguard Workertemplate_feature_enum = u"""{VarName},""" 95*8975f5c5SAndroid Build Coastguard Worker 96*8975f5c5SAndroid Build Coastguard Workertemplate_feature_list_source = u"""// GENERATED FILE - DO NOT EDIT. 97*8975f5c5SAndroid Build Coastguard Worker// Generated by {script_name} using data from {input_file_name}. 98*8975f5c5SAndroid Build Coastguard Worker// 99*8975f5c5SAndroid Build Coastguard Worker// Copyright 2022 The ANGLE Project Authors. All rights reserved. 100*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be 101*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file. 102*8975f5c5SAndroid Build Coastguard Worker// 103*8975f5c5SAndroid Build Coastguard Worker// angle_features_autogen.cpp: List of ANGLE features to help enable/disable them in tests. 104*8975f5c5SAndroid Build Coastguard Worker 105*8975f5c5SAndroid Build Coastguard Worker#include "angle_features_autogen.h" 106*8975f5c5SAndroid Build Coastguard Worker 107*8975f5c5SAndroid Build Coastguard Worker#include "common/PackedEnums.h" 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Workernamespace angle 110*8975f5c5SAndroid Build Coastguard Worker{{ 111*8975f5c5SAndroid Build Coastguard Workernamespace 112*8975f5c5SAndroid Build Coastguard Worker{{ 113*8975f5c5SAndroid Build Coastguard Workerconstexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{{{ 114*8975f5c5SAndroid Build Coastguard Worker{features} 115*8975f5c5SAndroid Build Coastguard Worker}}}}; 116*8975f5c5SAndroid Build Coastguard Worker}} // anonymous namespace 117*8975f5c5SAndroid Build Coastguard Worker 118*8975f5c5SAndroid Build Coastguard Workerconst char *GetFeatureName(Feature feature) 119*8975f5c5SAndroid Build Coastguard Worker{{ 120*8975f5c5SAndroid Build Coastguard Worker return kFeatureNames[feature]; 121*8975f5c5SAndroid Build Coastguard Worker}} 122*8975f5c5SAndroid Build Coastguard Worker 123*8975f5c5SAndroid Build Coastguard Worker}} // namespace angle 124*8975f5c5SAndroid Build Coastguard Worker""" 125*8975f5c5SAndroid Build Coastguard Worker 126*8975f5c5SAndroid Build Coastguard Workertemplate_feature_string = u""" {{Feature::{VarName}, "{display_name}"}},""" 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Worker 129*8975f5c5SAndroid Build Coastguard Workerdef make_camel_case(json_name): 130*8975f5c5SAndroid Build Coastguard Worker assert '_' in json_name, 'feature names in the json file are expected to be in snake_case' 131*8975f5c5SAndroid Build Coastguard Worker return re.sub('_(.)', lambda m: m.group(1).upper(), json_name) 132*8975f5c5SAndroid Build Coastguard Worker 133*8975f5c5SAndroid Build Coastguard Worker 134*8975f5c5SAndroid Build Coastguard Workerdef make_header_name(class_name): 135*8975f5c5SAndroid Build Coastguard Worker return class_name + '_autogen.h' 136*8975f5c5SAndroid Build Coastguard Worker 137*8975f5c5SAndroid Build Coastguard Worker 138*8975f5c5SAndroid Build Coastguard Workerdef header_path(class_name): 139*8975f5c5SAndroid Build Coastguard Worker return 'autogen/' + make_header_name(class_name) 140*8975f5c5SAndroid Build Coastguard Worker 141*8975f5c5SAndroid Build Coastguard Worker 142*8975f5c5SAndroid Build Coastguard Workerdef write_or_verify_file(filename, content, verify_only): 143*8975f5c5SAndroid Build Coastguard Worker if verify_only: 144*8975f5c5SAndroid Build Coastguard Worker try: 145*8975f5c5SAndroid Build Coastguard Worker with open(filename) as f: 146*8975f5c5SAndroid Build Coastguard Worker # Note: .gitattributes "* text=auto" handles LF <-> CRLF on Windows 147*8975f5c5SAndroid Build Coastguard Worker return f.read() == content 148*8975f5c5SAndroid Build Coastguard Worker except FileNotFoundError: 149*8975f5c5SAndroid Build Coastguard Worker return False 150*8975f5c5SAndroid Build Coastguard Worker else: 151*8975f5c5SAndroid Build Coastguard Worker with open(filename, 'w') as fout: 152*8975f5c5SAndroid Build Coastguard Worker fout.write(content) 153*8975f5c5SAndroid Build Coastguard Worker return True 154*8975f5c5SAndroid Build Coastguard Worker 155*8975f5c5SAndroid Build Coastguard Worker 156*8975f5c5SAndroid Build Coastguard Workerdef main(): 157*8975f5c5SAndroid Build Coastguard Worker if len(sys.argv) == 2 and sys.argv[1] == 'inputs': 158*8975f5c5SAndroid Build Coastguard Worker print(','.join(list(feature_files.keys()))) 159*8975f5c5SAndroid Build Coastguard Worker return 160*8975f5c5SAndroid Build Coastguard Worker if len(sys.argv) == 2 and sys.argv[1] == 'outputs': 161*8975f5c5SAndroid Build Coastguard Worker print(','.join([header_path(class_name) for (_, class_name) in feature_files.values()]) + 162*8975f5c5SAndroid Build Coastguard Worker ',' + feature_list_header_file + ',' + feature_list_source_file) 163*8975f5c5SAndroid Build Coastguard Worker return 164*8975f5c5SAndroid Build Coastguard Worker 165*8975f5c5SAndroid Build Coastguard Worker # --verify-only enables dirty checks without relying on checked in hashes. 166*8975f5c5SAndroid Build Coastguard Worker # Compares the content of the existing file with the generated content. 167*8975f5c5SAndroid Build Coastguard Worker verify_only = '--verify-only' in sys.argv 168*8975f5c5SAndroid Build Coastguard Worker 169*8975f5c5SAndroid Build Coastguard Worker name_map = {} 170*8975f5c5SAndroid Build Coastguard Worker 171*8975f5c5SAndroid Build Coastguard Worker for src_file, (category_prefix, class_name) in feature_files.items(): 172*8975f5c5SAndroid Build Coastguard Worker with open(src_file) as fin: 173*8975f5c5SAndroid Build Coastguard Worker src = json.loads(fin.read()) 174*8975f5c5SAndroid Build Coastguard Worker 175*8975f5c5SAndroid Build Coastguard Worker features_json = src['features'] 176*8975f5c5SAndroid Build Coastguard Worker features = [] 177*8975f5c5SAndroid Build Coastguard Worker 178*8975f5c5SAndroid Build Coastguard Worker # Go over the list of features and write the header file that declares the features struct 179*8975f5c5SAndroid Build Coastguard Worker for feature_json in features_json: 180*8975f5c5SAndroid Build Coastguard Worker json_name = feature_json['name'] 181*8975f5c5SAndroid Build Coastguard Worker var_name = make_camel_case(json_name) 182*8975f5c5SAndroid Build Coastguard Worker # Use the same (camelCase) name for display as well 183*8975f5c5SAndroid Build Coastguard Worker display_name = var_name 184*8975f5c5SAndroid Build Coastguard Worker feature = template_feature.format( 185*8975f5c5SAndroid Build Coastguard Worker var_name=var_name, 186*8975f5c5SAndroid Build Coastguard Worker display_name=display_name, 187*8975f5c5SAndroid Build Coastguard Worker category=category_prefix + feature_json['category']) 188*8975f5c5SAndroid Build Coastguard Worker 189*8975f5c5SAndroid Build Coastguard Worker features.append(feature) 190*8975f5c5SAndroid Build Coastguard Worker 191*8975f5c5SAndroid Build Coastguard Worker # Keep track of the feature names. Sometimes the same feature name is present in 192*8975f5c5SAndroid Build Coastguard Worker # multiple backends. That's ok for the purposes of feature overriding. 193*8975f5c5SAndroid Build Coastguard Worker name_map[var_name] = display_name 194*8975f5c5SAndroid Build Coastguard Worker 195*8975f5c5SAndroid Build Coastguard Worker description = '\n'.join( 196*8975f5c5SAndroid Build Coastguard Worker ['//' + (' ' + line if line else '') for line in src['description']]) 197*8975f5c5SAndroid Build Coastguard Worker header_file = make_header_name(class_name) 198*8975f5c5SAndroid Build Coastguard Worker 199*8975f5c5SAndroid Build Coastguard Worker header = template_header.format( 200*8975f5c5SAndroid Build Coastguard Worker script_name=os.path.basename(__file__), 201*8975f5c5SAndroid Build Coastguard Worker input_file_name=src_file, 202*8975f5c5SAndroid Build Coastguard Worker description=description.replace(src_file, header_file), 203*8975f5c5SAndroid Build Coastguard Worker name=class_name, 204*8975f5c5SAndroid Build Coastguard Worker NAME=class_name.upper(), 205*8975f5c5SAndroid Build Coastguard Worker features='\n'.join(features)) 206*8975f5c5SAndroid Build Coastguard Worker 207*8975f5c5SAndroid Build Coastguard Worker if not write_or_verify_file(header_path(class_name), header, verify_only): 208*8975f5c5SAndroid Build Coastguard Worker return 1 209*8975f5c5SAndroid Build Coastguard Worker 210*8975f5c5SAndroid Build Coastguard Worker # Generate helpers for use by tests to override a feature or not. 211*8975f5c5SAndroid Build Coastguard Worker feature_enums = [] 212*8975f5c5SAndroid Build Coastguard Worker feature_strings = [] 213*8975f5c5SAndroid Build Coastguard Worker for var_name, display_name in sorted(name_map.items(), key=lambda item: item[0].lower()): 214*8975f5c5SAndroid Build Coastguard Worker VarName = var_name[0].upper() + var_name[1:] 215*8975f5c5SAndroid Build Coastguard Worker 216*8975f5c5SAndroid Build Coastguard Worker feature_enums.append(template_feature_enum.format(VarName=VarName)) 217*8975f5c5SAndroid Build Coastguard Worker 218*8975f5c5SAndroid Build Coastguard Worker feature_strings.append( 219*8975f5c5SAndroid Build Coastguard Worker template_feature_string.format(VarName=VarName, display_name=display_name)) 220*8975f5c5SAndroid Build Coastguard Worker 221*8975f5c5SAndroid Build Coastguard Worker if not write_or_verify_file( 222*8975f5c5SAndroid Build Coastguard Worker feature_list_header_file, 223*8975f5c5SAndroid Build Coastguard Worker template_feature_list_header.format( 224*8975f5c5SAndroid Build Coastguard Worker script_name=os.path.basename(__file__), 225*8975f5c5SAndroid Build Coastguard Worker input_file_name='*_features.json', 226*8975f5c5SAndroid Build Coastguard Worker features='\n'.join(' ' + v for v in feature_enums)), verify_only): 227*8975f5c5SAndroid Build Coastguard Worker return 1 228*8975f5c5SAndroid Build Coastguard Worker 229*8975f5c5SAndroid Build Coastguard Worker if not write_or_verify_file( 230*8975f5c5SAndroid Build Coastguard Worker feature_list_source_file, 231*8975f5c5SAndroid Build Coastguard Worker template_feature_list_source.format( 232*8975f5c5SAndroid Build Coastguard Worker script_name=os.path.basename(__file__), 233*8975f5c5SAndroid Build Coastguard Worker input_file_name='*_features.json', 234*8975f5c5SAndroid Build Coastguard Worker features='\n'.join(feature_strings)), verify_only): 235*8975f5c5SAndroid Build Coastguard Worker return 1 236*8975f5c5SAndroid Build Coastguard Worker 237*8975f5c5SAndroid Build Coastguard Worker 238*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 239*8975f5c5SAndroid Build Coastguard Worker sys.exit(main()) 240