#!/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_interpreter_utils.py: # Code generator for the GLC interpreter. # NOTE: don't run this script directly. Run scripts/run_code_generation.py. import os import re import sys import registry_xml EXIT_SUCCESS = 0 EXIT_FAILURE = 1 BASE_PATH = '../util/capture/trace_interpreter_autogen' CPP_TEMPLATE = """\ // GENERATED FILE - DO NOT EDIT. // Generated by {script_name} using data from {data_source_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. // // {file_name}.cpp: // Helper code for trace interpreter. #include "angle_trace_gl.h" #include "trace_fixture.h" #include "trace_interpreter.h" namespace angle {{ CallCapture ParseCallCapture(const Token &nameToken, size_t numParamTokens, const Token *paramTokens, const TraceStringMap &strings) {{ {parse_cases} if (numParamTokens > 0) {{ printf("Expected zero parameter tokens for %s\\n", nameToken); UNREACHABLE(); }} return CallCapture(nameToken, ParamBuffer()); }} {dispatch_cases} void ReplayCustomFunctionCall(const CallCapture &call, const TraceFunctionMap &customFunctions) {{ ASSERT(call.entryPoint == EntryPoint::Invalid); const Captures &captures = call.params.getParamCaptures(); {custom_dispatch_cases} auto iter = customFunctions.find(call.customFunctionName); if (iter == customFunctions.end()) {{ printf("Unknown custom function: %s\\n", call.customFunctionName.c_str()); UNREACHABLE(); }} else {{ ASSERT(call.params.empty()); const TraceFunction &customFunc = iter->second; for (const CallCapture &customCall : customFunc) {{ ReplayTraceFunctionCall(customCall, customFunctions); }} }} }} }} // namespace angle """ PARSE_CASE = """\ if (strcmp(nameToken, "{ep}") == 0) {{ ParamBuffer params = ParseParameters<{pfn}>(paramTokens, strings); return CallCapture({call}, std::move(params)); }} """ CUSTOM_DISPATCH_CASE = """\ if (call.customFunctionName == "{fn}") {{ DispatchCallCapture({fn}, captures); return; }} """ DISPATCH_CASE = """\ template = 0> void DispatchCallCapture(Fn *fn, const Captures &cap) {{ (*fn)({args}); }} """ FIXTURE_H = '../util/capture/trace_fixture.h' def GetFunctionsFromFixture(): funcs = [] arg_counts = set() pattern = 'void ' with open(FIXTURE_H) as f: lines = f.read().split(';') for line in lines: line = re.sub('// .*\n', '', line.strip()) if line.startswith(pattern): func_name = line[len(pattern):line.find('(')] func_args = line.count(',') + 1 funcs.append(func_name) arg_counts.add(func_args) f.close() return sorted(funcs), arg_counts def get_dispatch(n): return ', '.join(['Arg(cap)' % i for i in range(n)]) def main(cpp_output_path): gles = registry_xml.GetGLES() egl = registry_xml.GetEGL() def fn(ep): return 'std::remove_pointer::type' % ep.upper() fixture_functions, arg_counts = GetFunctionsFromFixture() eps_and_enums = sorted(list(set(gles.GetEnums() + egl.GetEnums()))) parse_cases = [ PARSE_CASE.format(ep=ep, pfn=fn(ep), call='EntryPoint::%s' % enum) for (enum, ep) in eps_and_enums ] parse_cases += [ PARSE_CASE.format(ep=fn, pfn='decltype(%s)' % fn, call='"%s"' % fn) for fn in fixture_functions ] dispatch_cases = [DISPATCH_CASE.format(nargs=n, args=get_dispatch(n)) for n in arg_counts] custom_dispatch_cases = [CUSTOM_DISPATCH_CASE.format(fn=fn) for fn in fixture_functions] format_args = { 'script_name': os.path.basename(sys.argv[0]), 'data_source_name': 'gl.xml and gl_angle_ext.xml', 'file_name': os.path.basename(BASE_PATH), 'parse_cases': ''.join(parse_cases), 'dispatch_cases': '\n'.join(dispatch_cases), 'custom_dispatch_cases': ''.join(custom_dispatch_cases), } cpp_content = CPP_TEMPLATE.format(**format_args) cpp_output_path = registry_xml.script_relative(cpp_output_path) with open(cpp_output_path, 'w') as f: f.write(cpp_content) return EXIT_SUCCESS if __name__ == '__main__': inputs = registry_xml.xml_inputs + [FIXTURE_H] outputs = [ '%s.cpp' % BASE_PATH, ] if len(sys.argv) > 1: if sys.argv[1] == 'inputs': print(','.join(inputs)) elif sys.argv[1] == 'outputs': print(','.join(outputs)) else: sys.exit(main(registry_xml.script_relative(outputs[0])))