Path: blob/main_old/src/tests/restricted_traces/gen_restricted_traces.py
1693 views
#!/usr/bin/python31#2# Copyright 2020 The ANGLE Project Authors. All rights reserved.3# Use of this source code is governed by a BSD-style license that can be4# found in the LICENSE file.5#6# gen_restricted_traces.py:7# Generates integration code for the restricted trace tests.89import getpass10import glob11import fnmatch12import json13import os14import sys1516GNI_TEMPLATE = """\17# GENERATED FILE - DO NOT EDIT.18# Generated by {script_name} using data from {data_source_name}19#20# Copyright 2020 The ANGLE Project Authors. All rights reserved.21# Use of this source code is governed by a BSD-style license that can be22# found in the LICENSE file.23#24# A list of all restricted trace tests, paired with their context.25# Can be consumed by tests/BUILD.gn.2627angle_restricted_traces = [28{test_list}29]30"""3132HEADER_TEMPLATE = """\33// GENERATED FILE - DO NOT EDIT.34// Generated by {script_name} using data from {data_source_name}35//36// Copyright 2020 The ANGLE Project Authors. All rights reserved.37// Use of this source code is governed by a BSD-style license that can be38// found in the LICENSE file.39//40// {filename}: Types and enumerations for trace tests.4142#ifndef ANGLE_RESTRICTED_TRACES_AUTOGEN_H_43#define ANGLE_RESTRICTED_TRACES_AUTOGEN_H_4445#include <cstdint>46#include <vector>47#include <KHR/khrplatform.h>48#include <EGL/egl.h>4950#include "restricted_traces_export.h"5152namespace trace_angle53{{54using GenericProc = void (*)();55using LoadProc = GenericProc(KHRONOS_APIENTRY *)(const char *);56ANGLE_TRACE_LOADER_EXPORT void LoadEGL(LoadProc loadProc);57ANGLE_TRACE_LOADER_EXPORT void LoadGLES(LoadProc loadProc);58}} // namespace trace_angle5960namespace angle61{{62enum class RestrictedTraceID63{{64{trace_ids}, InvalidEnum, EnumCount = InvalidEnum65}};6667static constexpr size_t kTraceInfoMaxNameLen = 32;6869static constexpr uint32_t kDefaultReplayContextClientMajorVersion = 3;70static constexpr uint32_t kDefaultReplayContextClientMinorVersion = 1;71static constexpr uint32_t kDefaultReplayDrawSurfaceColorSpace = EGL_COLORSPACE_LINEAR;7273struct TraceInfo74{{75uint32_t contextClientMajorVersion;76uint32_t contextClientMinorVersion;77uint32_t startFrame;78uint32_t endFrame;79uint32_t drawSurfaceWidth;80uint32_t drawSurfaceHeight;81uint32_t drawSurfaceColorSpace;82char name[kTraceInfoMaxNameLen];83}};8485ANGLE_TRACE_EXPORT const TraceInfo &GetTraceInfo(RestrictedTraceID traceID);86}} // namespace angle8788#endif // ANGLE_RESTRICTED_TRACES_AUTOGEN_H_89"""9091SOURCE_TEMPLATE = """\92// GENERATED FILE - DO NOT EDIT.93// Generated by {script_name} using data from {data_source_name}94//95// Copyright 2020 The ANGLE Project Authors. All rights reserved.96// Use of this source code is governed by a BSD-style license that can be97// found in the LICENSE file.98//99// {filename}: Types and enumerations for trace tests.100101#include "{filename}.h"102103#include "common/PackedEnums.h"104#include "common/system_utils.h"105106{trace_includes}107108namespace angle109{{110namespace111{{112constexpr angle::PackedEnumMap<RestrictedTraceID, TraceInfo> kTraceInfos = {{113{trace_infos}114}};115}}116117const TraceInfo &GetTraceInfo(RestrictedTraceID traceID)118{{119return kTraceInfos[traceID];120}}121}} // namespace angle122"""123124CIPD_TRACE_PREFIX = 'angle/traces'125EXPERIMENTAL_CIPD_PREFIX = 'experimental/google.com/%s/angle/traces'126DEPS_PATH = '../../../DEPS'127DEPS_START = '# === ANGLE Restricted Trace Generated Code Start ==='128DEPS_END = '# === ANGLE Restricted Trace Generated Code End ==='129DEPS_TEMPLATE = """\130'src/tests/restricted_traces/{trace}': {{131'packages': [132{{133'package': '{trace_prefix}/{trace}',134'version': 'version:{version}',135}},136],137'dep_type': 'cipd',138'condition': 'checkout_angle_restricted_traces',139}},140"""141142143def reject_duplicate_keys(pairs):144found_keys = {}145for key, value in pairs:146if key in found_keys:147raise ValueError("duplicate key: %r" % (key,))148else:149found_keys[key] = value150return found_keys151152153# TODO(http://anglebug.com/5878): Revert back to non-autogen'ed file names for the angledata.gz.154def get_angledata_filename(trace):155angledata_files = glob.glob('%s/%s*angledata.gz' % (trace, trace))156assert len(angledata_files) == 1, "Trace '%s' has %d angledata.gz files" % (157trace, len(angledata_files))158return angledata_files[0].replace('\\', '/')159160161def gen_gni(traces, gni_file, format_args):162test_list = []163for trace in traces:164context = get_context(trace)165angledata_file = get_angledata_filename(trace)166with open('%s/%s_capture_context%s_files.txt' % (trace, trace, context)) as f:167files = f.readlines()168f.close()169files = ['"%s/%s"' % (trace, file.strip()) for file in files]170test_list += ['["%s", %s, [%s], "%s"]' % (trace, context, ','.join(files), angledata_file)]171172format_args['test_list'] = ',\n'.join(test_list)173gni_data = GNI_TEMPLATE.format(**format_args)174with open(gni_file, "w") as out_file:175out_file.write(gni_data)176return True177178179def contains_string(trace, string):180"""Determines if the trace contains a string"""181for file in os.listdir(trace):182if fnmatch.fnmatch(file, '*.h'):183with open(os.path.join(trace, file)) as f:184if string in f.read():185return True186return False187188189def contains_context_version(trace):190"""Determines if the trace contains the major/minor context version"""191return contains_string(trace, 'kReplayContextClientMajorVersion')192193194def contains_colorspace(trace):195"""Determines if the trace contains an EGL surface color space"""196return contains_string(trace, 'kReplayDrawSurfaceColorSpace')197198199def get_trace_info(trace):200# Some traces don't contain major/minor version, so use defaults201info = []202if contains_context_version(trace):203info += [204f"{trace}::kReplayContextClientMajorVersion",205f"{trace}::kReplayContextClientMinorVersion"206]207else:208info += [209"kDefaultReplayContextClientMajorVersion", "kDefaultReplayContextClientMinorVersion"210]211212info += [213f"{trace}::kReplayFrameStart", f"{trace}::kReplayFrameEnd",214f"{trace}::kReplayDrawSurfaceWidth", f"{trace}::kReplayDrawSurfaceHeight"215]216217if contains_colorspace(trace):218info += [f"{trace}::kReplayDrawSurfaceColorSpace"]219else:220info += ["kDefaultReplayDrawSurfaceColorSpace"]221222info += [f"\"{trace}\""]223224return ", ".join(info)225226227def get_context(trace):228"""Returns the context number used by trace txt file"""229for file in os.listdir(trace):230# Load up the only header present for each trace231if fnmatch.fnmatch(file, '*.txt'):232# Strip the extension to isolate the context by scanning233# for numbers leading up to the last one, i.e.:234# app_capture_context123_files.txt235# ^^236# start---||---end237start = len(file) - 11238end = start + 1239while file[start - 1].isdigit():240start -= 1241context = file[start:end]242assert context.isnumeric(), "Failed to find trace context number"243return context244245246def get_header_name(trace):247return "%s/%s_capture_context%s.h" % (trace, trace, get_context(trace))248249250def get_source_name(trace):251return "%s/%s_capture_context%s.cpp" % (trace, trace, get_context(trace))252253254def gen_header(header_file, format_args):255header_data = HEADER_TEMPLATE.format(**format_args)256with open(header_file, "w") as out_file:257out_file.write(header_data)258return True259260261def gen_source(source_file, format_args):262source_data = SOURCE_TEMPLATE.format(**format_args)263with open(source_file, "w") as out_file:264out_file.write(source_data)265return True266267268def gen_git_ignore(traces):269ignores = ['%s/' % trace for trace in traces]270with open('.gitignore', 'w') as out_file:271out_file.write('\n'.join(sorted(ignores)))272return True273274275def read_json(json_file):276with open(json_file) as map_file:277return json.loads(map_file.read(), object_pairs_hook=reject_duplicate_keys)278279280def update_deps(trace_pairs):281# Generate substitution string282replacement = ""283for (trace, version) in trace_pairs:284if 'x' in version:285version = version.strip('x')286trace_prefix = EXPERIMENTAL_CIPD_PREFIX % getpass.getuser()287else:288trace_prefix = CIPD_TRACE_PREFIX289sub = {'trace': trace, 'version': version, 'trace_prefix': trace_prefix}290replacement += DEPS_TEMPLATE.format(**sub)291292# Update DEPS to download CIPD dependencies293new_deps = ""294with open(DEPS_PATH) as f:295in_deps = False296for line in f:297if in_deps:298if DEPS_END in line:299new_deps += replacement300new_deps += line301in_deps = False302else:303if DEPS_START in line:304new_deps += line305in_deps = True306else:307new_deps += line308f.close()309310with open(DEPS_PATH, 'w') as f:311f.write(new_deps)312f.close()313314return True315316317def main():318json_file = 'restricted_traces.json'319gni_file = 'restricted_traces_autogen.gni'320header_file = 'restricted_traces_autogen.h'321source_file = 'restricted_traces_autogen.cpp'322323json_data = read_json(json_file)324if 'traces' not in json_data:325print('Trace data missing traces key.')326return 1327trace_pairs = [trace.split(' ') for trace in json_data['traces']]328traces = [trace_pair[0] for trace_pair in trace_pairs]329330# auto_script parameters.331if len(sys.argv) > 1:332inputs = [json_file]333334# Note: we do not include DEPS in the list of outputs to simplify the integration.335# Otherwise we'd continually need to regenerate on any roll.336outputs = [gni_file, header_file, source_file, '.gitignore']337338if sys.argv[1] == 'inputs':339print(','.join(inputs))340elif sys.argv[1] == 'outputs':341print(','.join(outputs))342else:343print('Invalid script parameters.')344return 1345return 0346347format_args = {348"script_name": os.path.basename(__file__),349"data_source_name": json_file,350}351352if not gen_gni(traces, gni_file, format_args):353print('.gni file generation failed.')354return 1355356includes = ["#include \"%s\"" % get_header_name(trace) for trace in traces]357trace_infos = [358"{RestrictedTraceID::%s, {%s}}" % (trace, get_trace_info(trace)) for trace in traces359]360361format_args["filename"] = "restricted_traces_autogen"362format_args["trace_ids"] = ",\n".join(traces)363format_args["trace_includes"] = "\n".join(includes)364format_args["trace_infos"] = ",\n".join(trace_infos)365if not gen_header(header_file, format_args):366print('.h file generation failed.')367return 1368369if not gen_source(source_file, format_args):370print('.cpp file generation failed.')371return 1372373if not gen_git_ignore(traces):374print('.gitignore file generation failed')375return 1376377if not update_deps(trace_pairs):378print('DEPS file update failed')379return 1380381return 0382383384if __name__ == '__main__':385sys.exit(main())386387388