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