blob: 53117f08280534c96d9b6da5d9c6cd86fd810235 [file] [log] [blame]
#!/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())