xref: /aosp_15_r20/external/angle/include/platform/gen_features.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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