| #!/usr/bin/python |
| # Copyright 2016 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_angle_format_table.py: |
| # Code generation for ANGLE format map. |
| # NOTE: don't run this script directly. Run scripts/run_code_generation.py. |
| # |
| |
| import angle_format |
| from datetime import date |
| import json |
| import math |
| import pprint |
| import re |
| import sys |
| |
| template_autogen_h = """// 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. |
| // |
| // ANGLE format enumeration. |
| |
| #ifndef LIBANGLE_RENDERER_FORMATID_H_ |
| #define LIBANGLE_RENDERER_FORMATID_H_ |
| |
| #include <cstdint> |
| |
| namespace angle |
| {{ |
| |
| enum class FormatID |
| {{ |
| {angle_format_enum} |
| }}; |
| |
| constexpr uint32_t kNumANGLEFormats = {num_angle_formats}; |
| |
| }} // namespace angle |
| |
| #endif // LIBANGLE_RENDERER_FORMATID_H_ |
| """ |
| |
| template_autogen_inl = """// 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. |
| // |
| // ANGLE Format table: |
| // Queries for typed format information from the ANGLE format enum. |
| |
| #include "libANGLE/renderer/Format.h" |
| |
| #include "image_util/copyimage.h" |
| #include "image_util/generatemip.h" |
| #include "image_util/loadimage.h" |
| |
| namespace angle |
| {{ |
| |
| static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {{angle::FormatID::R8G8B8A8_UNORM, |
| CopyBGRA8ToRGBA8}}; |
| static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {{&BGRAEntry, 1}}; |
| static constexpr rx::FastCopyFunctionMap NoCopyFunctions; |
| |
| const Format gFormatInfoTable[] = {{ |
| // clang-format off |
| {{ FormatID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false, gl::VertexAttribType::InvalidEnum }}, |
| {angle_format_info_cases} // clang-format on |
| }}; |
| |
| // static |
| FormatID Format::InternalFormatToID(GLenum internalFormat) |
| {{ |
| switch (internalFormat) |
| {{ |
| {angle_format_switch} |
| }} |
| }} |
| |
| const Format *GetFormatInfoTable() |
| {{ |
| return gFormatInfoTable; |
| }} |
| }} // namespace angle |
| """ |
| |
| |
| def ceil_int(value, mod): |
| assert mod > 0 and value > 0, 'integer modulation should be larger than 0' |
| return (value + mod - 1) / mod |
| |
| |
| def is_depth_stencil(angle_format): |
| if not 'channels' in angle_format or not angle_format['channels']: |
| return False |
| return 'd' in angle_format['channels'] or 's' in angle_format['channels'] |
| |
| |
| def get_component_suffix(angle_format): |
| if angle_format['componentType'] == 'float': |
| return 'F' |
| if angle_format['componentType'] == 'int' or angle_format['componentType'] == 'snorm': |
| return 'S' |
| return "" |
| |
| |
| def get_channel_struct(angle_format): |
| if 'bits' not in angle_format or angle_format['bits'] is None: |
| return None |
| if 'BLOCK' in angle_format['id']: |
| return None |
| if 'VERTEX' in angle_format['id']: |
| return None |
| |
| bits = angle_format['bits'] |
| |
| if 'channelStruct' in angle_format: |
| return angle_format['channelStruct'] |
| |
| struct_name = '' |
| component_suffix = get_component_suffix(angle_format) |
| |
| for channel in angle_format['channels']: |
| if channel == 'r': |
| struct_name += 'R{}'.format(bits['R']) |
| if channel == 'g': |
| struct_name += 'G{}'.format(bits['G']) |
| if channel == 'b': |
| struct_name += 'B{}'.format(bits['B']) |
| if channel == 'a': |
| struct_name += 'A{}'.format(bits['A']) |
| if channel == 'l': |
| struct_name += 'L{}'.format(bits['L']) |
| if channel == 'd': |
| struct_name += 'D{}'.format(bits['D']) + component_suffix |
| if channel == 's': |
| struct_name += 'S{}'.format(bits['S']) |
| if channel == 'x': |
| struct_name += 'X{}'.format(bits['X']) |
| |
| if not is_depth_stencil(angle_format): |
| struct_name += component_suffix |
| |
| return struct_name |
| |
| |
| def get_mip_generation_function(angle_format): |
| channel_struct = get_channel_struct(angle_format) |
| if is_depth_stencil(angle_format) or channel_struct == None \ |
| or "BLOCK" in angle_format["id"] or "VERTEX" in angle_format["id"]: |
| return 'nullptr' |
| return 'GenerateMip<' + channel_struct + '>' |
| |
| |
| def get_color_read_write_component_type(angle_format): |
| component_type_map = { |
| 'uint': 'GLuint', |
| 'int': 'GLint', |
| 'unorm': 'GLfloat', |
| 'snorm': 'GLfloat', |
| 'float': 'GLfloat' |
| } |
| return component_type_map[angle_format['componentType']] |
| |
| |
| def get_color_read_function(angle_format): |
| channel_struct = get_channel_struct(angle_format) |
| if channel_struct == None: |
| return 'nullptr' |
| |
| if is_depth_stencil(angle_format): |
| return 'ReadDepthStencil<' + channel_struct + '>' |
| |
| read_component_type = get_color_read_write_component_type(angle_format) |
| return 'ReadColor<' + channel_struct + ', ' + read_component_type + '>' |
| |
| |
| def get_color_write_function(angle_format): |
| channel_struct = get_channel_struct(angle_format) |
| if channel_struct == None: |
| return 'nullptr' |
| |
| if is_depth_stencil(angle_format): |
| return 'WriteDepthStencil<' + channel_struct + '>' |
| |
| write_component_type = get_color_read_write_component_type(angle_format) |
| return 'WriteColor<' + channel_struct + ', ' + write_component_type + '>' |
| |
| |
| format_entry_template = """ {{ FormatID::{id}, {glInternalFormat}, {fboImplementationInternalFormat}, {mipGenerationFunction}, {fastCopyFunctions}, {colorReadFunction}, {colorWriteFunction}, {namedComponentType}, {R}, {G}, {B}, {A}, {L}, {D}, {S}, {pixelBytes}, {componentAlignmentMask}, {isBlock}, {isFixed}, {isScaled}, {vertexAttribType} }}, |
| """ |
| |
| |
| def get_named_component_type(component_type): |
| if component_type == "snorm": |
| return "GL_SIGNED_NORMALIZED" |
| elif component_type == "unorm": |
| return "GL_UNSIGNED_NORMALIZED" |
| elif component_type == "float": |
| return "GL_FLOAT" |
| elif component_type == "uint": |
| return "GL_UNSIGNED_INT" |
| elif component_type == "int": |
| return "GL_INT" |
| elif component_type == "none": |
| return "GL_NONE" |
| else: |
| raise ValueError("Unknown component type for " + component_type) |
| |
| |
| def get_component_alignment_mask(channels, bits): |
| if channels == None or bits == None: |
| return "std::numeric_limits<GLuint>::max()" |
| bitness = bits[channels[0].upper()] |
| for channel in channels: |
| if channel not in "rgba": |
| return "std::numeric_limits<GLuint>::max()" |
| # Can happen for RGB10A2 formats. |
| if bits[channel.upper()] != bitness: |
| return "std::numeric_limits<GLuint>::max()" |
| component_bytes = (int(bitness) >> 3) |
| |
| if component_bytes == 1: |
| return "0" |
| elif component_bytes == 2: |
| return "1" |
| elif component_bytes == 4: |
| return "3" |
| else: |
| # Can happen for 4-bit RGBA. |
| return "std::numeric_limits<GLuint>::max()" |
| |
| |
| def get_vertex_attrib_type(format_id): |
| |
| has_u = "_U" in format_id |
| has_s = "_S" in format_id |
| has_float = "_FLOAT" in format_id |
| has_fixed = "_FIXED" in format_id |
| has_r8 = "R8" in format_id |
| has_r16 = "R16" in format_id |
| has_r32 = "R32" in format_id |
| has_r10 = "R10" in format_id |
| has_vertex = "VERTEX" in format_id |
| |
| if has_fixed: |
| return "Fixed" |
| |
| if has_float: |
| return "HalfFloat" if has_r16 else "Float" |
| |
| if has_r8: |
| return "Byte" if has_s else "UnsignedByte" |
| |
| if has_r10: |
| if has_vertex: |
| return "Int1010102" if has_s else "UnsignedInt1010102" |
| else: |
| return "Int2101010" if has_s else "UnsignedInt2101010" |
| |
| if has_r16: |
| return "Short" if has_s else "UnsignedShort" |
| |
| if has_r32: |
| return "Int" if has_s else "UnsignedInt" |
| |
| # Many ANGLE formats don't correspond with vertex formats. |
| return "InvalidEnum" |
| |
| |
| def json_to_table_data(format_id, json, angle_to_gl): |
| |
| table_data = "" |
| |
| parsed = { |
| "id": format_id, |
| "fastCopyFunctions": "NoCopyFunctions", |
| } |
| |
| for k, v in json.iteritems(): |
| parsed[k] = v |
| |
| if "glInternalFormat" not in parsed: |
| parsed["glInternalFormat"] = angle_to_gl[format_id] |
| |
| if "fboImplementationInternalFormat" not in parsed: |
| parsed["fboImplementationInternalFormat"] = parsed["glInternalFormat"] |
| |
| if "componentType" not in parsed: |
| parsed["componentType"] = angle_format.get_component_type(format_id) |
| |
| if "channels" not in parsed: |
| parsed["channels"] = angle_format.get_channels(format_id) |
| |
| if "bits" not in parsed: |
| parsed["bits"] = angle_format.get_bits(format_id) |
| |
| # Derived values. |
| parsed["mipGenerationFunction"] = get_mip_generation_function(parsed) |
| parsed["colorReadFunction"] = get_color_read_function(parsed) |
| parsed["colorWriteFunction"] = get_color_write_function(parsed) |
| |
| for channel in angle_format.kChannels: |
| if parsed["bits"] != None and channel in parsed["bits"]: |
| parsed[channel] = parsed["bits"][channel] |
| else: |
| parsed[channel] = "0" |
| |
| parsed["namedComponentType"] = get_named_component_type(parsed["componentType"]) |
| |
| if format_id == "B8G8R8A8_UNORM": |
| parsed["fastCopyFunctions"] = "BGRACopyFunctions" |
| |
| is_block = format_id.endswith("_BLOCK") |
| |
| pixel_bytes = 0 |
| if is_block: |
| assert 'blockPixelBytes' in parsed, \ |
| 'Compressed format %s requires its block size to be specified in angle_format_data.json' % \ |
| format_id |
| pixel_bytes = parsed['blockPixelBytes'] |
| else: |
| sum_of_bits = 0 |
| for channel in angle_format.kChannels: |
| sum_of_bits += int(parsed[channel]) |
| pixel_bytes = ceil_int(sum_of_bits, 8) |
| parsed["pixelBytes"] = pixel_bytes |
| parsed["componentAlignmentMask"] = get_component_alignment_mask(parsed["channels"], |
| parsed["bits"]) |
| parsed["isBlock"] = "true" if is_block else "false" |
| parsed["isFixed"] = "true" if "FIXED" in format_id else "false" |
| parsed["isScaled"] = "true" if "SCALED" in format_id else "false" |
| |
| parsed["vertexAttribType"] = "gl::VertexAttribType::" + get_vertex_attrib_type(format_id) |
| |
| return format_entry_template.format(**parsed) |
| |
| |
| def parse_angle_format_table(all_angle, json_data, angle_to_gl): |
| table_data = '' |
| for format_id in sorted(all_angle): |
| if format_id != "NONE": |
| format_info = json_data[format_id] if format_id in json_data else {} |
| table_data += json_to_table_data(format_id, format_info, angle_to_gl) |
| |
| return table_data |
| |
| |
| def gen_enum_string(all_angle): |
| enum_data = ' NONE' |
| for format_id in sorted(all_angle): |
| if format_id == 'NONE': |
| continue |
| enum_data += ',\n ' + format_id |
| return enum_data |
| |
| |
| case_template = """ case {gl_format}: |
| return FormatID::{angle_format}; |
| """ |
| |
| |
| def gen_map_switch_string(gl_to_angle): |
| switch_data = '' |
| for gl_format in sorted(gl_to_angle.keys()): |
| angle_format = gl_to_angle[gl_format] |
| switch_data += case_template.format(gl_format=gl_format, angle_format=angle_format) |
| switch_data += " default:\n" |
| switch_data += " return FormatID::NONE;" |
| return switch_data |
| |
| |
| def main(): |
| |
| # auto_script parameters. |
| if len(sys.argv) > 1: |
| inputs = ['angle_format.py', 'angle_format_data.json', 'angle_format_map.json'] |
| outputs = ['Format_table_autogen.cpp', 'FormatID_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 |
| |
| gl_to_angle = angle_format.load_forward_table('angle_format_map.json') |
| angle_to_gl = angle_format.load_inverse_table('angle_format_map.json') |
| data_source_name = 'angle_format_data.json' |
| json_data = angle_format.load_json(data_source_name) |
| all_angle = angle_to_gl.keys() |
| |
| angle_format_cases = parse_angle_format_table(all_angle, json_data, angle_to_gl) |
| switch_data = gen_map_switch_string(gl_to_angle) |
| output_cpp = template_autogen_inl.format( |
| script_name=sys.argv[0], |
| copyright_year=date.today().year, |
| angle_format_info_cases=angle_format_cases, |
| angle_format_switch=switch_data, |
| data_source_name=data_source_name) |
| with open('Format_table_autogen.cpp', 'wt') as out_file: |
| out_file.write(output_cpp) |
| out_file.close() |
| |
| enum_data = gen_enum_string(all_angle) |
| num_angle_formats = len(all_angle) |
| output_h = template_autogen_h.format( |
| script_name=sys.argv[0], |
| copyright_year=date.today().year, |
| angle_format_enum=enum_data, |
| data_source_name=data_source_name, |
| num_angle_formats=num_angle_formats) |
| with open('FormatID_autogen.h', 'wt') as out_file: |
| out_file.write(output_h) |
| out_file.close() |
| |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |