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