1#!/usr/bin/python2 2# 3# Copyright 2020 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_restricted_traces.py: 8# Generates integration code for the restricted trace tests. 9 10import fnmatch 11import json 12import os 13import sys 14 15gni_template = """# GENERATED FILE - DO NOT EDIT. 16# Generated by {script_name} using data from {data_source_name} 17# 18# Copyright 2020 The ANGLE Project Authors. All rights reserved. 19# Use of this source code is governed by a BSD-style license that can be 20# found in the LICENSE file. 21# 22# A list of all restricted trace tests, paired with their context. 23# Can be consumed by tests/BUILD.gn. 24 25angle_restricted_traces = [ 26{test_list} 27] 28""" 29 30header_template = """// GENERATED FILE - DO NOT EDIT. 31// Generated by {script_name} using data from {data_source_name} 32// 33// Copyright 2020 The ANGLE Project Authors. All rights reserved. 34// Use of this source code is governed by a BSD-style license that can be 35// found in the LICENSE file. 36// 37// Types and enumerations for trace tests. 38 39#ifndef ANGLE_RESTRICTED_TRACES_H_ 40#define ANGLE_RESTRICTED_TRACES_H_ 41 42{includes} 43 44namespace angle 45{{ 46enum class RestrictedTraceID 47{{ 48{trace_ids}, InvalidEnum, EnumCount = InvalidEnum 49}}; 50 51using ReplayFunc = void (*)(uint32_t); 52using ResetFunc = void (*)(); 53using SetupFunc = void (*)(); 54using DecompressFunc = uint8_t *(*)(const std::vector<uint8_t> &); 55using SetBinaryDataDirFunc = void (*)(const char *); 56 57static constexpr size_t kTraceInfoMaxNameLen = 32; 58 59struct TraceInfo 60{{ 61 uint32_t startFrame; 62 uint32_t endFrame; 63 char name[kTraceInfoMaxNameLen]; 64}}; 65 66constexpr angle::PackedEnumMap<RestrictedTraceID, TraceInfo> kTraceInfos = {{ 67{trace_infos} 68}}; 69 70using DecompressCallback = uint8_t *(*)(const std::vector<uint8_t> &); 71using FramebufferChangeCallback = void(*)(void *userData, GLenum target, GLuint framebuffer); 72 73inline void ReplayFrame(RestrictedTraceID traceID, uint32_t frameIndex) 74{{ 75 switch (traceID) 76 {{ 77{replay_func_cases} 78 default: 79 fprintf(stderr, "Error in switch.\\n"); 80 assert(0); 81 break; 82 }} 83}} 84 85inline void ResetReplay(RestrictedTraceID traceID) 86{{ 87 switch (traceID) 88 {{ 89{reset_func_cases} 90 default: 91 fprintf(stderr, "Error in switch.\\n"); 92 assert(0); 93 break; 94 }} 95}} 96 97inline void SetupReplay(RestrictedTraceID traceID) 98{{ 99 switch (traceID) 100 {{ 101{setup_func_cases} 102 default: 103 fprintf(stderr, "Error in switch.\\n"); 104 assert(0); 105 break; 106 }} 107}} 108 109inline void SetBinaryDataDir(RestrictedTraceID traceID, const char *dataDir) 110{{ 111 switch (traceID) 112 {{ 113{set_binary_data_dir_cases} 114 default: 115 fprintf(stderr, "Error in switch.\\n"); 116 assert(0); 117 break; 118 }} 119}} 120 121inline void SetBinaryDataDecompressCallback(RestrictedTraceID traceID, DecompressCallback callback) 122{{ 123 switch (traceID) 124 {{ 125{decompress_callback_cases} 126 default: 127 fprintf(stderr, "Error in switch.\\n"); 128 assert(0); 129 break; 130 }} 131}} 132 133inline void SetFramebufferChangeCallback(RestrictedTraceID traceID, void *userData, FramebufferChangeCallback callback) 134{{ 135 switch (traceID) 136 {{ 137{on_fb_change_callback_cases} 138 default: 139 fprintf(stderr, "Error in switch.\\n"); 140 assert(0); 141 break; 142 }} 143}} 144}} // namespace angle 145 146#endif // ANGLE_RESTRICTED_TRACES_H_ 147""" 148 149 150def reject_duplicate_keys(pairs): 151 found_keys = {} 152 for key, value in pairs: 153 if key in found_keys: 154 raise ValueError("duplicate key: %r" % (key,)) 155 else: 156 found_keys[key] = value 157 return found_keys 158 159 160def gen_gni(traces, gni_file, format_args): 161 format_args["test_list"] = ",\n".join( 162 ['"%s %s"' % (trace, get_context(trace)) for trace in traces]) 163 gni_data = gni_template.format(**format_args) 164 with open(gni_file, "w") as out_file: 165 out_file.write(gni_data) 166 return True 167 168 169def get_trace_info(trace): 170 info = ["%s::kReplayFrameStart", "%s::kReplayFrameEnd", "\"%s\""] 171 return ", ".join([element % trace for element in info]) 172 173 174def get_context(trace): 175 "Returns the context number used by trace header file" 176 for file in os.listdir(trace): 177 # Load up the only header present for each trace 178 if fnmatch.fnmatch(file, '*.h'): 179 # Strip the extension to isolate the context 180 context = file[len(file) - 3] 181 assert context.isdigit() == True, "Failed to find trace context number" 182 assert file[len(file) - 4].isdigit() == False, "Context number is higher than 9" 183 return context 184 185 186def get_cases(traces, function, args): 187 funcs = [ 188 "case RestrictedTraceID::%s: %s::%s(%s); break;" % (trace, trace, function, args) 189 for trace in traces 190 ] 191 return "\n".join(funcs) 192 193 194def get_header_name(trace): 195 return "%s/%s_capture_context%s.h" % (trace, trace, get_context(trace)) 196 197 198def get_sha1_name(trace): 199 return "%s.tar.gz.sha1" % trace 200 201 202def get_cases_with_context(traces, function_start, function_end, args): 203 funcs = [ 204 "case RestrictedTraceID::%s: %s::%s%s%s(%s); break;" % 205 (trace, trace, function_start, get_context(trace), function_end, args) for trace in traces 206 ] 207 return "\n".join(funcs) 208 209 210def gen_header(traces, header_file, format_args): 211 212 includes = ["#include \"%s\"" % get_header_name(trace) for trace in traces] 213 trace_infos = [ 214 "{RestrictedTraceID::%s, {%s}}" % (trace, get_trace_info(trace)) for trace in traces 215 ] 216 217 format_args["includes"] = "\n".join(includes) 218 format_args["trace_ids"] = ",\n".join(traces) 219 format_args["trace_infos"] = ",\n".join(trace_infos) 220 format_args["replay_func_cases"] = get_cases_with_context(traces, "ReplayContext", "Frame", 221 "frameIndex") 222 format_args["reset_func_cases"] = get_cases_with_context(traces, "ResetContext", "Replay", "") 223 format_args["setup_func_cases"] = get_cases_with_context(traces, "SetupContext", "Replay", "") 224 format_args["set_binary_data_dir_cases"] = get_cases(traces, "SetBinaryDataDir", "dataDir") 225 format_args["decompress_callback_cases"] = get_cases(traces, "SetBinaryDataDecompressCallback", 226 "callback") 227 format_args["on_fb_change_callback_cases"] = get_cases(traces, "SetFramebufferChangeCallback", 228 "userData, callback") 229 header_data = header_template.format(**format_args) 230 with open(header_file, "w") as out_file: 231 out_file.write(header_data) 232 return True 233 234 235def read_json(json_file): 236 with open(json_file) as map_file: 237 return json.loads(map_file.read(), object_pairs_hook=reject_duplicate_keys) 238 239 240def main(): 241 json_file = 'restricted_traces.json' 242 gni_file = 'restricted_traces_autogen.gni' 243 header_file = 'restricted_traces_autogen.h' 244 245 json_data = read_json(json_file) 246 if 'traces' not in json_data: 247 print('Trace data missing traces key.') 248 return 1 249 traces = json_data['traces'] 250 251 # auto_script parameters. 252 if len(sys.argv) > 1: 253 inputs = [json_file] + [get_sha1_name(trace) for trace in traces] 254 outputs = [gni_file, header_file] 255 256 if sys.argv[1] == 'inputs': 257 print ','.join(inputs) 258 elif sys.argv[1] == 'outputs': 259 print ','.join(outputs) 260 else: 261 print('Invalid script parameters.') 262 return 1 263 return 0 264 265 format_args = { 266 "script_name": __file__, 267 "data_source_name": json_file, 268 } 269 270 if not gen_gni(traces, gni_file, format_args): 271 print('.gni file generation failed.') 272 return 1 273 274 if not gen_header(traces, header_file, format_args): 275 print('.h file generation failed.') 276 return 1 277 278 return 0 279 280 281if __name__ == '__main__': 282 sys.exit(main()) 283