• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2#
3# Copyright 2018 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# generate_loader.py:
8#   Generates dynamic loaders for various binding interfaces.
9#   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
10
11import sys, os, pprint, json
12import registry_xml
13
14
15DEFAULT_INTERNAL_PREFIX = "l_"
16
17
18def write_header(data_source_name,
19                 all_cmds,
20                 api,
21                 preamble,
22                 path,
23                 lib,
24                 ns="",
25                 prefix=None,
26                 export="",
27                 internal_prefix=DEFAULT_INTERNAL_PREFIX,
28                 file_prefix=""):
29    file_name = "%s%s_loader_autogen.h" % (file_prefix, api)
30    header_path = registry_xml.path_to(path, file_name)
31
32    def pre(cmd):
33        if prefix == None:
34            return cmd
35        return prefix + cmd[len(api):]
36
37    with open(header_path, "w") as out:
38        defines = [
39            "#define %s%s %s%s%s" % (ns, pre(cmd), internal_prefix, ns, pre(cmd))
40            for cmd in all_cmds
41        ]
42        var_protos = [
43            "%sextern PFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd))
44            for cmd in all_cmds
45        ]
46        loader_header = template_loader_h.format(
47            script_name=os.path.basename(sys.argv[0]),
48            data_source_name=data_source_name,
49            defines="\n".join(defines),
50            function_pointers="\n".join(var_protos),
51            api_upper=api.upper(),
52            api_lower=api,
53            preamble=preamble,
54            export=export,
55            lib=lib.upper(),
56            load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()),
57            file_prefix=file_prefix)
58
59        out.write(loader_header)
60        out.close()
61
62
63def write_source(data_source_name,
64                 all_cmds,
65                 api,
66                 path,
67                 ns="",
68                 prefix=None,
69                 export="",
70                 internal_prefix=DEFAULT_INTERNAL_PREFIX,
71                 file_prefix=""):
72    file_name = "%s%s_loader_autogen.cpp" % (file_prefix, api)
73    source_path = registry_xml.path_to(path, file_name)
74
75    def pre(cmd):
76        if prefix == None:
77            return cmd
78        return prefix + cmd[len(api):]
79
80    with open(source_path, "w") as out:
81        var_defs = [
82            "%sPFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd))
83            for cmd in all_cmds
84        ]
85
86        setter = "    %s%s%s = reinterpret_cast<PFN%sPROC>(loadProc(\"%s\"));"
87        setters = [
88            setter % (internal_prefix, ns, pre(cmd), cmd.upper(), pre(cmd)) for cmd in all_cmds
89        ]
90
91        loader_source = template_loader_cpp.format(
92            script_name=os.path.basename(sys.argv[0]),
93            data_source_name=data_source_name,
94            function_pointers="\n".join(var_defs),
95            set_pointers="\n".join(setters),
96            api_upper=api.upper(),
97            api_lower=api,
98            load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()),
99            file_prefix=file_prefix)
100
101        out.write(loader_source)
102        out.close()
103
104
105def gen_libegl_loader():
106
107    data_source_name = "egl.xml and egl_angle_ext.xml"
108    xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml")
109
110    for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]:
111        annotation = "{}_{}".format(major_version, minor_version)
112        name_prefix = "EGL_VERSION_"
113
114        feature_name = "{}{}".format(name_prefix, annotation)
115
116        xml.AddCommands(feature_name, annotation)
117
118    xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl'])
119
120    all_cmds = xml.all_cmd_names.get_all_commands()
121
122    path = os.path.join("..", "src", "libEGL")
123    write_header(
124        data_source_name,
125        all_cmds,
126        "egl",
127        libegl_preamble,
128        path,
129        "LIBEGL",
130        prefix="EGL_",
131        export="ANGLE_NO_EXPORT ")
132    write_source(data_source_name, all_cmds, "egl", path, prefix="EGL_")
133
134
135def gen_gles_loader(gles_preamble, path, header_lib, export, internal_prefix, file_prefix):
136
137    data_source_name = "gl.xml and gl_angle_ext.xml"
138    xml = registry_xml.RegistryXML("gl.xml", "gl_angle_ext.xml")
139
140    # First run through the main GLES entry points.  Since ES2+ is the primary use
141    # case, we go through those first and then add ES1-only APIs at the end.
142    for major_version, minor_version in [[2, 0], [3, 0], [3, 1], [3, 2], [1, 0]]:
143        annotation = "{}_{}".format(major_version, minor_version)
144        name_prefix = "GL_ES_VERSION_"
145
146        is_gles1 = major_version == 1
147        if is_gles1:
148            name_prefix = "GL_VERSION_ES_CM_"
149
150        feature_name = "{}{}".format(name_prefix, annotation)
151
152        xml.AddCommands(feature_name, annotation)
153
154    xml.AddExtensionCommands(registry_xml.supported_extensions, ['gles2', 'gles1'])
155
156    all_cmds = xml.all_cmd_names.get_all_commands()
157
158    # Ensure there are no duplicates
159    assert (len(all_cmds) == len(set(all_cmds))), "Duplicate command names found"
160
161    write_header(
162        data_source_name,
163        all_cmds,
164        "gles",
165        gles_preamble,
166        path,
167        header_lib,
168        export=export,
169        internal_prefix=internal_prefix,
170        file_prefix=file_prefix)
171    write_source(
172        data_source_name,
173        all_cmds,
174        "gles",
175        path,
176        export=export,
177        internal_prefix=internal_prefix,
178        file_prefix=file_prefix)
179
180
181def gen_egl_loader(egl_preamble, path, header_lib, export, internal_prefix, file_prefix):
182
183    data_source_name = "egl.xml and egl_angle_ext.xml"
184    xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml")
185
186    for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]:
187        annotation = "{}_{}".format(major_version, minor_version)
188        name_prefix = "EGL_VERSION_"
189
190        feature_name = "{}{}".format(name_prefix, annotation)
191
192        xml.AddCommands(feature_name, annotation)
193
194    xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl'])
195
196    all_cmds = xml.all_cmd_names.get_all_commands()
197
198    write_header(
199        data_source_name,
200        all_cmds,
201        "egl",
202        egl_preamble,
203        path,
204        header_lib,
205        export=export,
206        internal_prefix=internal_prefix,
207        file_prefix=file_prefix)
208    write_source(
209        data_source_name,
210        all_cmds,
211        "egl",
212        path,
213        export=export,
214        internal_prefix=internal_prefix,
215        file_prefix=file_prefix)
216
217
218def gen_util_gles_and_egl_loaders():
219    path = os.path.join("..", "util")
220    export = "ANGLE_UTIL_EXPORT "
221    lib = "UTIL"
222    gen_gles_loader(util_gles_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "")
223    gen_egl_loader(util_egl_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "")
224
225
226def gen_trace_gles_and_egl_loaders():
227    path = os.path.join("..", "src", "tests", "restricted_traces")
228    export = "ANGLE_TRACE_LOADER_EXPORT "
229    lib = "ANGLE_RESTRICTED_TRACES"
230    gen_gles_loader(trace_gles_preamble, path, lib, export, "t_", "trace_")
231    gen_egl_loader(trace_egl_preamble, path, lib, export, "t_", "trace_")
232
233
234def gen_util_wgl_loader():
235
236    supported_wgl_extensions = [
237        "WGL_ARB_create_context",
238        "WGL_ARB_extensions_string",
239        "WGL_EXT_swap_control",
240    ]
241
242    source = "wgl.xml"
243    xml = registry_xml.RegistryXML(source)
244
245    for major_version, minor_version in [[1, 0]]:
246        annotation = "{}_{}".format(major_version, minor_version)
247        name_prefix = "WGL_VERSION_"
248
249        feature_name = "{}{}".format(name_prefix, annotation)
250
251        xml.AddCommands(feature_name, annotation)
252
253    xml.AddExtensionCommands(supported_wgl_extensions, ['wgl'])
254
255    all_cmds = xml.all_cmd_names.get_all_commands()
256
257    path = os.path.join("..", "util", "windows")
258    write_header(source, all_cmds, "wgl", util_wgl_preamble, path, "UTIL_WINDOWS", "_")
259    write_source(source, all_cmds, "wgl", path, "_")
260
261
262def main():
263
264    # Handle inputs/outputs for run_code_generation.py's auto_script
265    if len(sys.argv) > 1:
266        inputs = registry_xml.xml_inputs
267        outputs = [
268            '../src/libEGL/egl_loader_autogen.cpp',
269            '../src/libEGL/egl_loader_autogen.h',
270            '../util/egl_loader_autogen.cpp',
271            '../util/egl_loader_autogen.h',
272            '../util/gles_loader_autogen.cpp',
273            '../util/gles_loader_autogen.h',
274            '../util/windows/wgl_loader_autogen.cpp',
275            '../util/windows/wgl_loader_autogen.h',
276            '../src/tests/restricted_traces/trace_egl_loader_autogen.cpp',
277            '../src/tests/restricted_traces/trace_egl_loader_autogen.h',
278            '../src/tests/restricted_traces/trace_gles_loader_autogen.cpp',
279            '../src/tests/restricted_traces/trace_gles_loader_autogen.h',
280        ]
281
282        if sys.argv[1] == 'inputs':
283            print(','.join(inputs))
284        elif sys.argv[1] == 'outputs':
285            print(','.join(outputs))
286        else:
287            print('Invalid script parameters')
288            return 1
289        return 0
290
291    gen_libegl_loader()
292    gen_util_gles_and_egl_loaders()
293    gen_util_wgl_loader()
294    gen_trace_gles_and_egl_loaders()
295    return 0
296
297
298libegl_preamble = """#include <EGL/egl.h>
299#include <EGL/eglext.h>
300#include <export.h>
301"""
302
303util_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES
304#error "Don't define GL prototypes if you want to use a loader!"
305#endif  // defined(GL_GLES_PROTOTYPES)
306
307#include "angle_gl.h"
308#include "util/util_export.h"
309"""
310
311util_egl_preamble = """#include "util/util_export.h"
312
313#include <EGL/egl.h>
314#include <EGL/eglext.h>
315"""
316
317trace_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES
318#error "Don't define GL prototypes if you want to use a loader!"
319#endif  // defined(GL_GLES_PROTOTYPES)
320
321#include "angle_gl.h"
322#include "restricted_traces_autogen.h"
323"""
324
325trace_egl_preamble = """#include "restricted_traces_autogen.h"
326
327#include <EGL/egl.h>
328#include <EGL/eglext.h>
329"""
330
331util_wgl_preamble = """
332#include <WGL/wgl.h>
333#include <GLES2/gl2.h>
334
335// We add an underscore before each function name to ensure common names like "ChoosePixelFormat"
336// and "SwapBuffers" don't conflict with our function pointers. We can't use a namespace because
337// some functions conflict with preprocessor definitions.
338"""
339
340template_loader_h = """// GENERATED FILE - DO NOT EDIT.
341// Generated by {script_name} using data from {data_source_name}.
342//
343// Copyright 2018 The ANGLE Project Authors. All rights reserved.
344// Use of this source code is governed by a BSD-style license that can be
345// found in the LICENSE file.
346//
347// {api_lower}_loader_autogen.h:
348//   Simple {api_upper} function loader.
349
350#ifndef {lib}_{api_upper}_LOADER_AUTOGEN_H_
351#define {lib}_{api_upper}_LOADER_AUTOGEN_H_
352
353{preamble}
354{defines}
355{function_pointers}
356
357namespace {file_prefix}angle
358{{
359using GenericProc = void (*)();
360using LoadProc = GenericProc (KHRONOS_APIENTRY *)(const char *);
361{export}void {load_fn_name}(LoadProc loadProc);
362}}  // namespace angle
363
364#endif  // {lib}_{api_upper}_LOADER_AUTOGEN_H_
365"""
366
367template_loader_cpp = """// GENERATED FILE - DO NOT EDIT.
368// Generated by {script_name} using data from {data_source_name}.
369//
370// Copyright 2018 The ANGLE Project Authors. All rights reserved.
371// Use of this source code is governed by a BSD-style license that can be
372// found in the LICENSE file.
373//
374// {api_lower}_loader_autogen.cpp:
375//   Simple {api_upper} function loader.
376
377#include "{file_prefix}{api_lower}_loader_autogen.h"
378
379{function_pointers}
380
381namespace {file_prefix}angle
382{{
383void {load_fn_name}(LoadProc loadProc)
384{{
385{set_pointers}
386}}
387}}  // namespace angle
388"""
389
390if __name__ == '__main__':
391    sys.exit(main())
392