Edit

kc3-lang/angle/src/common/gen_packed_gl_enums.py

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-06-26 16:19:34
    Hash : 485cdd8b
    Message : Add std::ostream output for packed enums. This can be used to convert them to strings for debugging. It can also be helpful for frame capture and replay. Currently the enums are output as GLenum values. Bug: angleproject:3611 Change-Id: Ifcd04449e0ef61e125e0db65aa0dcc2bf48b38ca Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1678399 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/common/gen_packed_gl_enums.py
  • # 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.
    #
    # gen_packed_gl_enums.py:
    #   Code generation for the packed enums.
    #   NOTE: don't run this script directly. Run scripts/run_code_generation.py.
    
    import datetime, json, os, sys
    from collections import namedtuple
    from collections import OrderedDict
    
    Enum = namedtuple('Enum', ['name', 'values', 'max_value'])
    EnumValue = namedtuple('EnumValue', ['name', 'gl_name', 'value'])
    
    Generators = [
        {
            'json': 'packed_gl_enums.json',
            'output': 'PackedGLEnums',
            'namespace': 'gl',
            'enum_type': 'GLenum',
        },
        {
            'json': 'packed_egl_enums.json',
            'output': 'PackedEGLEnums',
            'namespace': 'egl',
            'enum_type': 'EGLenum',
        },
    ]
    
    
    def load_enums(path):
        with open(path) as map_file:
            enums_dict = json.loads(map_file.read(), object_pairs_hook=OrderedDict)
    
        enums = []
        for (enum_name, value_list) in enums_dict.iteritems():
    
            values = []
            i = 0
    
            for (value_name, value_gl_name) in value_list.iteritems():
                values.append(EnumValue(value_name, value_gl_name, i))
                i += 1
    
            assert (i < 255)  # This makes sure enums fit in the uint8_t
            enums.append(Enum(enum_name, values, i))
    
        enums.sort(key=lambda enum: enum.name)
        return enums
    
    
    def generate_include_guard(path):
        return path.replace(".", "_").upper()
    
    
    def header_name_from_cpp_name(path):
        return path.replace(".cpp", ".h")
    
    
    header_template = """// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using data from {data_source_name}.
    //
    // Copyright {copyright_year} 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}:
    //   Declares ANGLE-specific enums classes for {api_enum_name}s and functions operating
    //   on them.
    
    #ifndef COMMON_{include_guard}_
    #define COMMON_{include_guard}_
    
    #include <angle_gl.h>
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    
    #include <cstdint>
    #include <ostream>
    
    namespace {namespace}
    {{
    
    template<typename Enum>
    Enum From{api_enum_name}({api_enum_name} from);
    {content}
    }}  // namespace {namespace}
    
    #endif // COMMON_{include_guard}_
    """
    
    enum_declaration_template = """
    enum class {enum_name} : uint8_t
    {{
    {value_declarations}
    
        InvalidEnum = {max_value},
        EnumCount = {max_value},
    }};
    
    template <>
    {enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from);
    {api_enum_name} To{api_enum_name}({enum_name} from);
    std::ostream &operator<<(std::ostream &os, {enum_name} value);
    """
    
    
    def write_header(enums, path_prefix, file_name, data_source_name, namespace, api_enum_name):
        content = ['']
    
        for enum in enums:
            value_declarations = []
            for value in enum.values:
                value_declarations.append('    ' + value.name + ' = ' + str(value.value) + ',')
    
            content.append(
                enum_declaration_template.format(
                    enum_name=enum.name,
                    max_value=str(enum.max_value),
                    value_declarations='\n'.join(value_declarations),
                    api_enum_name=api_enum_name))
    
        header = header_template.format(
            content=''.join(content),
            copyright_year=datetime.date.today().year,
            data_source_name=data_source_name,
            script_name=sys.argv[0],
            file_name=file_name,
            include_guard=generate_include_guard(file_name),
            namespace=namespace,
            api_enum_name=api_enum_name)
    
        with (open(path_prefix + file_name, 'wt')) as f:
            f.write(header)
    
    
    cpp_template = """// GENERATED FILE - DO NOT EDIT.
    // Generated by {script_name} using data from {data_source_name}.
    //
    // Copyright {copyright_year} 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}:
    //   Implements ANGLE-specific enums classes for {api_enum_name}s and functions operating
    //   on them.
    
    #include "common/debug.h"
    #include "common/{header_name}"
    
    namespace {namespace}
    {{
    {content}
    }}  // namespace {namespace}
    """
    
    enum_implementation_template = """
    template <>
    {enum_name} From{api_enum_name}<{enum_name}>({api_enum_name} from)
    {{
        switch (from)
        {{
    {from_glenum_cases}
            default:
                return {enum_name}::InvalidEnum;
        }}
    }}
    
    {api_enum_name} To{api_enum_name}({enum_name} from)
    {{
        switch (from)
        {{
    {to_glenum_cases}
            default:
                UNREACHABLE();
                return 0;
        }}
    }}
    
    std::ostream &operator<<(std::ostream &os, {enum_name} value)
    {{
        switch (value)
        {{
    {ostream_cases}
            default:
                os << "GL_INVALID_ENUM";
                break;
        }}
        return os;
    }}
    """
    
    
    def write_cpp(enums, path_prefix, file_name, data_source_name, namespace, api_enum_name):
        content = ['']
    
        for enum in enums:
            from_glenum_cases = []
            to_glenum_cases = []
            ostream_cases = []
            for value in enum.values:
                qualified_name = enum.name + '::' + value.name
                from_glenum_cases.append('        case ' + value.gl_name + ':\n            return ' +
                                         qualified_name + ';')
                to_glenum_cases.append('        case ' + qualified_name + ':\n            return ' +
                                       value.gl_name + ';')
                ostream_cases.append('        case ' + qualified_name + ':\n            os << "' +
                                     value.gl_name + '";\n            break;')
    
            content.append(
                enum_implementation_template.format(
                    enum_name=enum.name,
                    from_glenum_cases='\n'.join(from_glenum_cases),
                    max_value=str(enum.max_value),
                    to_glenum_cases='\n'.join(to_glenum_cases),
                    api_enum_name=api_enum_name,
                    ostream_cases='\n'.join(ostream_cases)))
    
        cpp = cpp_template.format(
            content=''.join(content),
            copyright_year=datetime.date.today().year,
            data_source_name=data_source_name,
            script_name=sys.argv[0],
            file_name=file_name,
            header_name=header_name_from_cpp_name(file_name),
            namespace=namespace,
            api_enum_name=api_enum_name)
    
        with (open(path_prefix + file_name, 'wt')) as f:
            f.write(cpp)
    
    
    def main():
    
        # auto_script parameters.
        if len(sys.argv) > 1:
            inputs = []
            outputs = []
            for generator in Generators:
                inputs += [generator['json']]
                outputs += [
                    generator['output'] + '_autogen.cpp',
                    generator['output'] + '_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
    
        path_prefix = os.path.dirname(os.path.realpath(__file__)) + os.path.sep
    
        for generator in Generators:
            json_file = generator['json']
            output_file = generator['output']
            namespace = generator['namespace']
            enum_type = generator['enum_type']
            enums = load_enums(path_prefix + json_file)
            write_header(enums, path_prefix, output_file + '_autogen.h', json_file, namespace,
                         enum_type)
            write_cpp(enums, path_prefix, output_file + '_autogen.cpp', json_file, namespace,
                      enum_type)
        return 0
    
    
    if __name__ == '__main__':
        sys.exit(main())