222 lines
6.5 KiB
Python
Executable File
222 lines
6.5 KiB
Python
Executable File
#! /usr/bin/python3
|
|
|
|
# Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
#
|
|
# gen_features.py:
|
|
# Code generation for ANGLE features.
|
|
# NOTE: don't run this script directly. Run scripts/run_code_generation.py.
|
|
|
|
from collections import namedtuple
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
feature_files = {
|
|
'd3d_features.json': ('D3D', 'FeaturesD3D'),
|
|
'frontend_features.json': ('Frontend', 'FrontendFeatures'),
|
|
'gl_features.json': ('OpenGL', 'FeaturesGL'),
|
|
'mtl_features.json': ('Metal', 'FeaturesMtl'),
|
|
'vk_features.json': ('Vulkan', 'FeaturesVk'),
|
|
}
|
|
feature_list_header_file = '../../util/angle_features_autogen.h'
|
|
feature_list_source_file = '../../util/angle_features_autogen.cpp'
|
|
|
|
template_header = u"""// GENERATED FILE - DO NOT EDIT.
|
|
// Generated by {script_name} using data from {input_file_name}.
|
|
//
|
|
{description}
|
|
|
|
#ifndef ANGLE_PLATFORM_{NAME}_H_
|
|
#define ANGLE_PLATFORM_{NAME}_H_
|
|
|
|
#include "platform/Feature.h"
|
|
|
|
namespace angle
|
|
{{
|
|
|
|
struct {name} : FeatureSetBase
|
|
{{
|
|
{name}();
|
|
~{name}();
|
|
|
|
{features}
|
|
}};
|
|
|
|
inline {name}::{name}() = default;
|
|
inline {name}::~{name}() = default;
|
|
|
|
}} // namespace angle
|
|
|
|
#endif // ANGLE_PLATFORM_{NAME}_H_
|
|
"""
|
|
|
|
template_feature = u"""FeatureInfo {var_name} = {{
|
|
"{display_name}", FeatureCategory::{category},
|
|
{description},
|
|
&members, {issue}
|
|
}};
|
|
"""
|
|
|
|
template_feature_list_header = u"""// GENERATED FILE - DO NOT EDIT.
|
|
// Generated by {script_name} using data from {input_file_name}.
|
|
//
|
|
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// angle_features_autogen.h: List of ANGLE features to help enable/disable them in tests.
|
|
|
|
#ifndef ANGLE_SRC_TESTS_TEST_UTILS_ANGLE_FEATURES_AUTOGEN_H_
|
|
#define ANGLE_SRC_TESTS_TEST_UTILS_ANGLE_FEATURES_AUTOGEN_H_
|
|
|
|
#include "util_export.h"
|
|
|
|
namespace angle
|
|
{{
|
|
enum class Feature
|
|
{{
|
|
{features}
|
|
|
|
InvalidEnum,
|
|
EnumCount = InvalidEnum,
|
|
}};
|
|
|
|
ANGLE_UTIL_EXPORT extern const char *GetFeatureName(Feature feature);
|
|
|
|
}} // namespace angle
|
|
|
|
#endif // ANGLE_SRC_TESTS_TEST_UTILS_ANGLE_FEATURES_AUTOGEN_H_
|
|
"""
|
|
|
|
template_feature_enum = u"""{VarName},"""
|
|
|
|
template_feature_list_source = u"""// GENERATED FILE - DO NOT EDIT.
|
|
// Generated by {script_name} using data from {input_file_name}.
|
|
//
|
|
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// angle_features_autogen.cpp: List of ANGLE features to help enable/disable them in tests.
|
|
|
|
#include "angle_features_autogen.h"
|
|
|
|
#include "common/PackedEnums.h"
|
|
|
|
namespace angle
|
|
{{
|
|
namespace
|
|
{{
|
|
constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{ {{
|
|
{features}
|
|
}} }};
|
|
}} // anonymous namespace
|
|
|
|
const char *GetFeatureName(Feature feature)
|
|
{{
|
|
return kFeatureNames[feature];
|
|
}}
|
|
|
|
}} // namespace angle
|
|
"""
|
|
|
|
template_feature_string = u"""{{Feature::{VarName}, "{display_name}"}},"""
|
|
|
|
|
|
def make_camel_case(json_name):
|
|
assert '_' in json_name, 'feature names in the json file are expected to be in snake_case'
|
|
return re.sub('_(.)', lambda m: m.group(1).upper(), json_name)
|
|
|
|
|
|
def make_header_name(class_name):
|
|
return class_name + '_autogen.h'
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
|
|
print(','.join(list(feature_files.keys())))
|
|
return
|
|
if len(sys.argv) == 2 and sys.argv[1] == 'outputs':
|
|
print(','.join(
|
|
[make_header_name(class_name) for (_, class_name) in feature_files.values()]) + ',' +
|
|
feature_list_header_file + ',' + feature_list_source_file)
|
|
return
|
|
|
|
name_map = {}
|
|
|
|
for src_file, (category_prefix, class_name) in feature_files.items():
|
|
with open(src_file) as fin:
|
|
src = json.loads(fin.read())
|
|
|
|
features_json = src['features']
|
|
features = []
|
|
|
|
# Go over the list of features and write the header file that declares the features struct
|
|
for feature_json in features_json:
|
|
json_name = feature_json['name']
|
|
var_name = make_camel_case(json_name)
|
|
# Use the same (camelCase) name for display as well
|
|
display_name = var_name
|
|
issue = feature_json.get('issue', None)
|
|
feature = template_feature.format(
|
|
var_name=var_name,
|
|
display_name=display_name,
|
|
category=category_prefix + feature_json['category'],
|
|
description='\n'.join('"' + line + '"' for line in feature_json['description']),
|
|
issue='' if issue is None else '"' + issue + '"')
|
|
|
|
features.append(feature)
|
|
|
|
# Keep track of the feature names. Sometimes the same feature name is present in
|
|
# multiple backends. That's ok for the purposes of feature overriding.
|
|
name_map[var_name] = display_name
|
|
|
|
description = '\n'.join(['// ' + line for line in src['description']])
|
|
header_file = make_header_name(class_name)
|
|
|
|
header = template_header.format(
|
|
script_name=os.path.basename(__file__),
|
|
input_file_name=src_file,
|
|
description=description.replace(src_file, header_file),
|
|
name=class_name,
|
|
NAME=class_name.upper(),
|
|
features='\n'.join(features))
|
|
|
|
with open(header_file, 'w') as fout:
|
|
fout.write(header)
|
|
fout.close()
|
|
|
|
# Generate helpers for use by tests to override a feature or not.
|
|
feature_enums = []
|
|
feature_strings = []
|
|
for var_name, display_name in sorted(name_map.items(), key=lambda item: item[0].lower()):
|
|
VarName = var_name[0].upper() + var_name[1:]
|
|
|
|
feature_enums.append(template_feature_enum.format(VarName=VarName))
|
|
|
|
feature_strings.append(
|
|
template_feature_string.format(VarName=VarName, display_name=display_name))
|
|
|
|
with open(feature_list_header_file, 'w') as fout:
|
|
fout.write(
|
|
template_feature_list_header.format(
|
|
script_name=os.path.basename(__file__),
|
|
input_file_name='*_features.json',
|
|
features='\n'.join(feature_enums)))
|
|
fout.close()
|
|
|
|
with open(feature_list_source_file, 'w') as fout:
|
|
fout.write(
|
|
template_feature_list_source.format(
|
|
script_name=os.path.basename(__file__),
|
|
input_file_name='*_features.json',
|
|
features='\n'.join(feature_strings)))
|
|
fout.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|