• 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_interpreter_utils.py:
8#   Code generator for the GLC interpreter.
9#   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
10
11import os
12import re
13import sys
14
15import registry_xml
16
17EXIT_SUCCESS = 0
18EXIT_FAILURE = 1
19
20BASE_PATH = '../util/capture/trace_interpreter_autogen'
21
22CPP_TEMPLATE = """\
23// GENERATED FILE - DO NOT EDIT.
24// Generated by {script_name} using data from {data_source_name}.
25//
26// Copyright 2022 The ANGLE Project Authors. All rights reserved.
27// Use of this source code is governed by a BSD-style license that can be
28// found in the LICENSE file.
29//
30// {file_name}.cpp:
31//   Helper code for trace interpreter.
32
33#include "angle_trace_gl.h"
34#include "trace_fixture.h"
35#include "trace_interpreter.h"
36
37namespace angle
38{{
39CallCapture ParseCallCapture(const Token &nameToken, size_t numParamTokens, const Token *paramTokens, const TraceStringMap &strings)
40{{
41{parse_cases}
42    if (numParamTokens > 0)
43    {{
44        printf("Expected zero parameter tokens for %s\\n", nameToken);
45        UNREACHABLE();
46    }}
47    return CallCapture(nameToken, ParamBuffer());
48}}
49
50{dispatch_cases}
51
52void ReplayCustomFunctionCall(const CallCapture &call, const TraceFunctionMap &customFunctions)
53{{
54    ASSERT(call.entryPoint == EntryPoint::Invalid);
55    const Captures &captures = call.params.getParamCaptures();
56
57{custom_dispatch_cases}
58
59    auto iter = customFunctions.find(call.customFunctionName);
60    if (iter == customFunctions.end())
61    {{
62        printf("Unknown custom function: %s\\n", call.customFunctionName.c_str());
63        UNREACHABLE();
64    }}
65    else
66    {{
67        ASSERT(call.params.empty());
68        const TraceFunction &customFunc = iter->second;
69        for (const CallCapture &customCall : customFunc)
70        {{
71            ReplayTraceFunctionCall(customCall, customFunctions);
72        }}
73    }}
74}}
75}}  // namespace angle
76"""
77
78PARSE_CASE = """\
79    if (strcmp(nameToken, "{ep}") == 0)
80    {{
81        ParamBuffer params = ParseParameters<{pfn}>(paramTokens, strings);
82        return CallCapture({call}, std::move(params));
83    }}
84"""
85
86CUSTOM_DISPATCH_CASE = """\
87    if (call.customFunctionName == "{fn}")
88    {{
89        DispatchCallCapture({fn}, captures);
90        return;
91    }}
92"""
93
94DISPATCH_CASE = """\
95template <typename Fn, EnableIfNArgs<Fn, {nargs}> = 0>
96void DispatchCallCapture(Fn *fn, const Captures &cap)
97{{
98    (*fn)({args});
99}}
100"""
101
102FIXTURE_H = '../util/capture/trace_fixture.h'
103
104
105def GetFunctionsFromFixture():
106    funcs = []
107    arg_counts = set()
108    pattern = 'void '
109    with open(FIXTURE_H) as f:
110        lines = f.read().split(';')
111        for line in lines:
112            line = re.sub('// .*\n', '', line.strip())
113            if line.startswith(pattern):
114                func_name = line[len(pattern):line.find('(')]
115                func_args = line.count(',') + 1
116                funcs.append(func_name)
117                arg_counts.add(func_args)
118        f.close()
119    return sorted(funcs), arg_counts
120
121
122def get_dispatch(n):
123    return ', '.join(['Arg<Fn, %d>(cap)' % i for i in range(n)])
124
125
126def main(cpp_output_path):
127    gles = registry_xml.GetGLES()
128    egl = registry_xml.GetEGL()
129
130    def fn(ep):
131        return 'std::remove_pointer<PFN%sPROC>::type' % ep.upper()
132
133    fixture_functions, arg_counts = GetFunctionsFromFixture()
134
135    eps_and_enums = sorted(list(set(gles.GetEnums() + egl.GetEnums())))
136    parse_cases = [
137        PARSE_CASE.format(ep=ep, pfn=fn(ep), call='EntryPoint::%s' % enum)
138        for (enum, ep) in eps_and_enums
139    ]
140    parse_cases += [
141        PARSE_CASE.format(ep=fn, pfn='decltype(%s)' % fn, call='"%s"' % fn)
142        for fn in fixture_functions
143    ]
144
145    dispatch_cases = [DISPATCH_CASE.format(nargs=n, args=get_dispatch(n)) for n in arg_counts]
146
147    custom_dispatch_cases = [CUSTOM_DISPATCH_CASE.format(fn=fn) for fn in fixture_functions]
148
149    format_args = {
150        'script_name': os.path.basename(sys.argv[0]),
151        'data_source_name': 'gl.xml and gl_angle_ext.xml',
152        'file_name': os.path.basename(BASE_PATH),
153        'parse_cases': ''.join(parse_cases),
154        'dispatch_cases': '\n'.join(dispatch_cases),
155        'custom_dispatch_cases': ''.join(custom_dispatch_cases),
156    }
157
158    cpp_content = CPP_TEMPLATE.format(**format_args)
159    cpp_output_path = registry_xml.script_relative(cpp_output_path)
160    with open(cpp_output_path, 'w') as f:
161        f.write(cpp_content)
162
163    return EXIT_SUCCESS
164
165
166if __name__ == '__main__':
167    inputs = registry_xml.xml_inputs + [FIXTURE_H]
168    outputs = [
169        '%s.cpp' % BASE_PATH,
170    ]
171
172    if len(sys.argv) > 1:
173        if sys.argv[1] == 'inputs':
174            print(','.join(inputs))
175        elif sys.argv[1] == 'outputs':
176            print(','.join(outputs))
177    else:
178        sys.exit(main(registry_xml.script_relative(outputs[0])))
179