Edit

kc3-lang/angle/scripts/generate_loader.py

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2021-08-20 10:51:31
    Hash : 259ae49c
    Message : Capture/Replay: Isolate trace export definitions. This small fix to the export header means we no longer include the "restricted_traces_autogen.h" in each and every trace file. That means when we change/add/remove a trace we no longer need to recompile each and every trace. Speeds up iteration time when working with the traces. Also fixes inconsistent path generation on Windows. Bug: angleproject:5133 Change-Id: I357d65477a683455d01379379e2e98431af2ed55 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3110749 Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Tim Van Patten <timvp@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • scripts/generate_loader.py
  • #!/usr/bin/python3
    #
    # Copyright 2018 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.
    #
    # generate_loader.py:
    #   Generates dynamic loaders for various binding interfaces.
    #   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
    
    import sys, os, pprint, json
    import registry_xml
    
    
    DEFAULT_INTERNAL_PREFIX = "l_"
    
    
    def write_header(data_source_name,
                     all_cmds,
                     api,
                     preamble,
                     path,
                     lib,
                     ns="",
                     prefix=None,
                     export="",
                     internal_prefix=DEFAULT_INTERNAL_PREFIX,
                     file_prefix=""):
        file_name = "%s%s_loader_autogen.h" % (file_prefix, api)
        header_path = registry_xml.path_to(path, file_name)
    
        def pre(cmd):
            if prefix == None:
                return cmd
            return prefix + cmd[len(api):]
    
        with open(header_path, "w") as out:
            defines = [
                "#define %s%s %s%s%s" % (ns, pre(cmd), internal_prefix, ns, pre(cmd))
                for cmd in all_cmds
            ]
            var_protos = [
                "%sextern PFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd))
                for cmd in all_cmds
            ]
            loader_header = template_loader_h.format(
                script_name=os.path.basename(sys.argv[0]),
                data_source_name=data_source_name,
                defines="\n".join(defines),
                function_pointers="\n".join(var_protos),
                api_upper=api.upper(),
                api_lower=api,
                preamble=preamble,
                export=export,
                lib=lib.upper(),
                load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()),
                file_prefix=file_prefix)
    
            out.write(loader_header)
            out.close()
    
    
    def write_source(data_source_name,
                     all_cmds,
                     api,
                     path,
                     ns="",
                     prefix=None,
                     export="",
                     internal_prefix=DEFAULT_INTERNAL_PREFIX,
                     file_prefix=""):
        file_name = "%s%s_loader_autogen.cpp" % (file_prefix, api)
        source_path = registry_xml.path_to(path, file_name)
    
        def pre(cmd):
            if prefix == None:
                return cmd
            return prefix + cmd[len(api):]
    
        with open(source_path, "w") as out:
            var_defs = [
                "%sPFN%sPROC %s%s%s;" % (export, cmd.upper(), internal_prefix, ns, pre(cmd))
                for cmd in all_cmds
            ]
    
            setter = "    %s%s%s = reinterpret_cast<PFN%sPROC>(loadProc(\"%s\"));"
            setters = [
                setter % (internal_prefix, ns, pre(cmd), cmd.upper(), pre(cmd)) for cmd in all_cmds
            ]
    
            loader_source = template_loader_cpp.format(
                script_name=os.path.basename(sys.argv[0]),
                data_source_name=data_source_name,
                function_pointers="\n".join(var_defs),
                set_pointers="\n".join(setters),
                api_upper=api.upper(),
                api_lower=api,
                load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()),
                file_prefix=file_prefix)
    
            out.write(loader_source)
            out.close()
    
    
    def gen_libegl_loader():
    
        data_source_name = "egl.xml and egl_angle_ext.xml"
        xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml")
    
        for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]:
            annotation = "{}_{}".format(major_version, minor_version)
            name_prefix = "EGL_VERSION_"
    
            feature_name = "{}{}".format(name_prefix, annotation)
    
            xml.AddCommands(feature_name, annotation)
    
        xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl'])
    
        all_cmds = xml.all_cmd_names.get_all_commands()
    
        path = os.path.join("..", "src", "libEGL")
        write_header(
            data_source_name,
            all_cmds,
            "egl",
            libegl_preamble,
            path,
            "LIBEGL",
            prefix="EGL_",
            export="ANGLE_NO_EXPORT ")
        write_source(data_source_name, all_cmds, "egl", path, prefix="EGL_")
    
    
    def gen_gles_loader(gles_preamble, path, header_lib, export, internal_prefix, file_prefix):
    
        data_source_name = "gl.xml and gl_angle_ext.xml"
        xml = registry_xml.RegistryXML("gl.xml", "gl_angle_ext.xml")
    
        # First run through the main GLES entry points.  Since ES2+ is the primary use
        # case, we go through those first and then add ES1-only APIs at the end.
        for major_version, minor_version in [[2, 0], [3, 0], [3, 1], [3, 2], [1, 0]]:
            annotation = "{}_{}".format(major_version, minor_version)
            name_prefix = "GL_ES_VERSION_"
    
            is_gles1 = major_version == 1
            if is_gles1:
                name_prefix = "GL_VERSION_ES_CM_"
    
            feature_name = "{}{}".format(name_prefix, annotation)
    
            xml.AddCommands(feature_name, annotation)
    
        xml.AddExtensionCommands(registry_xml.supported_extensions, ['gles2', 'gles1'])
    
        all_cmds = xml.all_cmd_names.get_all_commands()
    
        # Ensure there are no duplicates
        assert (len(all_cmds) == len(set(all_cmds))), "Duplicate command names found"
    
        write_header(
            data_source_name,
            all_cmds,
            "gles",
            gles_preamble,
            path,
            header_lib,
            export=export,
            internal_prefix=internal_prefix,
            file_prefix=file_prefix)
        write_source(
            data_source_name,
            all_cmds,
            "gles",
            path,
            export=export,
            internal_prefix=internal_prefix,
            file_prefix=file_prefix)
    
    
    def gen_egl_loader(egl_preamble, path, header_lib, export, internal_prefix, file_prefix):
    
        data_source_name = "egl.xml and egl_angle_ext.xml"
        xml = registry_xml.RegistryXML("egl.xml", "egl_angle_ext.xml")
    
        for major_version, minor_version in [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]:
            annotation = "{}_{}".format(major_version, minor_version)
            name_prefix = "EGL_VERSION_"
    
            feature_name = "{}{}".format(name_prefix, annotation)
    
            xml.AddCommands(feature_name, annotation)
    
        xml.AddExtensionCommands(registry_xml.supported_egl_extensions, ['egl'])
    
        all_cmds = xml.all_cmd_names.get_all_commands()
    
        write_header(
            data_source_name,
            all_cmds,
            "egl",
            egl_preamble,
            path,
            header_lib,
            export=export,
            internal_prefix=internal_prefix,
            file_prefix=file_prefix)
        write_source(
            data_source_name,
            all_cmds,
            "egl",
            path,
            export=export,
            internal_prefix=internal_prefix,
            file_prefix=file_prefix)
    
    
    def gen_util_gles_and_egl_loaders():
        path = os.path.join("..", "util")
        export = "ANGLE_UTIL_EXPORT "
        lib = "UTIL"
        gen_gles_loader(util_gles_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "")
        gen_egl_loader(util_egl_preamble, path, lib, export, DEFAULT_INTERNAL_PREFIX, "")
    
    
    def gen_trace_gles_and_egl_loaders():
        path = os.path.join("..", "src", "tests", "restricted_traces")
        export = "ANGLE_TRACE_LOADER_EXPORT "
        lib = "ANGLE_RESTRICTED_TRACES"
        gen_gles_loader(trace_gles_preamble, path, lib, export, "t_", "trace_")
        gen_egl_loader(trace_egl_preamble, path, lib, export, "t_", "trace_")
    
    
    def gen_util_wgl_loader():
    
        supported_wgl_extensions = [
            "WGL_ARB_create_context",
            "WGL_ARB_extensions_string",
            "WGL_EXT_swap_control",
        ]
    
        source = "wgl.xml"
        xml = registry_xml.RegistryXML(source)
    
        for major_version, minor_version in [[1, 0]]:
            annotation = "{}_{}".format(major_version, minor_version)
            name_prefix = "WGL_VERSION_"
    
            feature_name = "{}{}".format(name_prefix, annotation)
    
            xml.AddCommands(feature_name, annotation)
    
        xml.AddExtensionCommands(supported_wgl_extensions, ['wgl'])
    
        all_cmds = xml.all_cmd_names.get_all_commands()
    
        path = os.path.join("..", "util", "windows")
        write_header(source, all_cmds, "wgl", util_wgl_preamble, path, "UTIL_WINDOWS", "_")
        write_source(source, all_cmds, "wgl", path, "_")
    
    
    def main():
    
        # Handle inputs/outputs for run_code_generation.py's auto_script
        if len(sys.argv) > 1:
            inputs = registry_xml.xml_inputs
            outputs = [
                '../src/libEGL/egl_loader_autogen.cpp',
                '../src/libEGL/egl_loader_autogen.h',
                '../util/egl_loader_autogen.cpp',
                '../util/egl_loader_autogen.h',
                '../util/gles_loader_autogen.cpp',
                '../util/gles_loader_autogen.h',
                '../util/windows/wgl_loader_autogen.cpp',
                '../util/windows/wgl_loader_autogen.h',
                '../src/tests/restricted_traces/trace_egl_loader_autogen.cpp',
                '../src/tests/restricted_traces/trace_egl_loader_autogen.h',
                '../src/tests/restricted_traces/trace_gles_loader_autogen.cpp',
                '../src/tests/restricted_traces/trace_gles_loader_autogen.h',
            ]
    
            if sys.argv[1] == 'inputs':
                print(','.join(inputs))
            elif sys.argv[1] == 'outputs':
                print(','.join(outputs))
            else:
                print('Invalid script parameters')
                return 1
            return 0
    
        gen_libegl_loader()
        gen_util_gles_and_egl_loaders()
        gen_util_wgl_loader()
        gen_trace_gles_and_egl_loaders()
        return 0
    
    
    libegl_preamble = """#include <EGL/egl.h>
    #include <EGL/eglext.h>
    #include <export.h>
    """
    
    util_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES
    #error "Don't define GL prototypes if you want to use a loader!"
    #endif  // defined(GL_GLES_PROTOTYPES)
    
    #include "angle_gl.h"
    #include "util/util_export.h"
    """
    
    util_egl_preamble = """#include "util/util_export.h"
    
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    """
    
    trace_gles_preamble = """#if defined(GL_GLES_PROTOTYPES) && GL_GLES_PROTOTYPES
    #error "Don't define GL prototypes if you want to use a loader!"
    #endif  // defined(GL_GLES_PROTOTYPES)
    
    #include "angle_gl.h"
    #include "restricted_traces_export.h"
    """
    
    trace_egl_preamble = """
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    
    #include "restricted_traces_export.h"
    """
    
    util_wgl_preamble = """
    #include <WGL/wgl.h>
    #include <GLES2/gl2.h>
    
    // We add an underscore before each function name to ensure common names like "ChoosePixelFormat"
    // and "SwapBuffers" don't conflict with our function pointers. We can't use a namespace because
    // some functions conflict with preprocessor definitions.
    """
    
    template_loader_h = """// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using data from {data_source_name}.
    //
    // Copyright 2018 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.
    //
    // {api_lower}_loader_autogen.h:
    //   Simple {api_upper} function loader.
    
    #ifndef {lib}_{api_upper}_LOADER_AUTOGEN_H_
    #define {lib}_{api_upper}_LOADER_AUTOGEN_H_
    
    {preamble}
    {defines}
    {function_pointers}
    
    namespace {file_prefix}angle
    {{
    using GenericProc = void (*)();
    using LoadProc = GenericProc (KHRONOS_APIENTRY *)(const char *);
    {export}void {load_fn_name}(LoadProc loadProc);
    }}  // namespace angle
    
    #endif  // {lib}_{api_upper}_LOADER_AUTOGEN_H_
    """
    
    template_loader_cpp = """// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using data from {data_source_name}.
    //
    // Copyright 2018 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.
    //
    // {api_lower}_loader_autogen.cpp:
    //   Simple {api_upper} function loader.
    
    #include "{file_prefix}{api_lower}_loader_autogen.h"
    
    {function_pointers}
    
    namespace {file_prefix}angle
    {{
    void {load_fn_name}(LoadProc loadProc)
    {{
    {set_pointers}
    }}
    }}  // namespace angle
    """
    
    if __name__ == '__main__':
        sys.exit(main())