1#!/usr/bin/python3 2# Copyright 2016 The ANGLE Project Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5# 6# gen_angle_format_table.py: 7# Code generation for ANGLE format map. 8# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 9# 10 11import angle_format 12import json 13import math 14import os 15import pprint 16import re 17import sys 18 19template_autogen_h = """// GENERATED FILE - DO NOT EDIT. 20// Generated by {script_name} using data from {data_source_name} 21// 22// Copyright 2020 The ANGLE Project Authors. All rights reserved. 23// Use of this source code is governed by a BSD-style license that can be 24// found in the LICENSE file. 25// 26// ANGLE format enumeration. 27 28#ifndef LIBANGLE_RENDERER_FORMATID_H_ 29#define LIBANGLE_RENDERER_FORMATID_H_ 30 31#include <cstdint> 32 33namespace angle 34{{ 35 36enum class FormatID 37{{ 38{angle_format_enum} 39}}; 40 41constexpr uint32_t kNumANGLEFormats = {num_angle_formats}; 42 43}} // namespace angle 44 45#endif // LIBANGLE_RENDERER_FORMATID_H_ 46""" 47 48template_autogen_inl = """// GENERATED FILE - DO NOT EDIT. 49// Generated by {script_name} using data from {data_source_name} 50// 51// Copyright 2020 The ANGLE Project Authors. All rights reserved. 52// Use of this source code is governed by a BSD-style license that can be 53// found in the LICENSE file. 54// 55// ANGLE Format table: 56// Queries for typed format information from the ANGLE format enum. 57 58#include "libANGLE/renderer/Format.h" 59 60#include "image_util/copyimage.h" 61#include "image_util/generatemip.h" 62#include "image_util/loadimage.h" 63 64namespace angle 65{{ 66 67static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {{angle::FormatID::R8G8B8A8_UNORM, 68 CopyBGRA8ToRGBA8}}; 69static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {{&BGRAEntry, 1}}; 70static constexpr rx::FastCopyFunctionMap NoCopyFunctions; 71 72const Format gFormatInfoTable[] = {{ 73 // clang-format off 74 {{ FormatID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false, false, false, gl::VertexAttribType::InvalidEnum }}, 75{angle_format_info_cases} // clang-format on 76}}; 77 78// static 79FormatID Format::InternalFormatToID(GLenum internalFormat) 80{{ 81 switch (internalFormat) 82 {{ 83{angle_format_switch} 84 }} 85}} 86 87const Format *GetFormatInfoTable() 88{{ 89 return gFormatInfoTable; 90}} 91}} // namespace angle 92""" 93 94 95def ceil_int(value, mod): 96 assert mod > 0 and value > 0, 'integer modulation should be larger than 0' 97 return (value + mod - 1) // mod 98 99 100def is_depth_stencil(angle_format): 101 if not 'channels' in angle_format or not angle_format['channels']: 102 return False 103 return 'd' in angle_format['channels'] or 's' in angle_format['channels'] 104 105 106def get_component_suffix(angle_format): 107 if angle_format['componentType'] == 'float': 108 return 'F' 109 if angle_format['componentType'] == 'int' or angle_format['componentType'] == 'snorm': 110 return 'S' 111 return "" 112 113 114def get_channel_struct(angle_format): 115 if 'bits' not in angle_format or angle_format['bits'] is None: 116 return None 117 if 'BLOCK' in angle_format['id']: 118 return None 119 if 'VERTEX' in angle_format['id']: 120 return None 121 if 'EXTERNAL' in angle_format['id']: 122 return None 123 124 bits = angle_format['bits'] 125 126 if 'channelStruct' in angle_format: 127 return angle_format['channelStruct'] 128 129 struct_name = '' 130 component_suffix = get_component_suffix(angle_format) 131 132 for channel in angle_format['channels']: 133 if channel == 'r': 134 struct_name += 'R{}'.format(bits['R']) 135 if channel == 'g': 136 struct_name += 'G{}'.format(bits['G']) 137 if channel == 'b': 138 struct_name += 'B{}'.format(bits['B']) 139 if channel == 'a': 140 struct_name += 'A{}'.format(bits['A']) 141 if channel == 'l': 142 struct_name += 'L{}'.format(bits['L']) 143 if channel == 'd': 144 struct_name += 'D{}'.format(bits['D']) + component_suffix 145 if channel == 's': 146 struct_name += 'S{}'.format(bits['S']) 147 if channel == 'x': 148 struct_name += 'X{}'.format(bits['X']) 149 150 if not is_depth_stencil(angle_format): 151 struct_name += component_suffix 152 153 return struct_name 154 155 156def get_mip_generation_function(angle_format): 157 channel_struct = get_channel_struct(angle_format) 158 if is_depth_stencil(angle_format) or channel_struct == None \ 159 or "BLOCK" in angle_format["id"] or "VERTEX" in angle_format["id"]: 160 return 'nullptr' 161 return 'GenerateMip<' + channel_struct + '>' 162 163 164def get_color_read_write_component_type(angle_format): 165 component_type_map = { 166 'uint': 'GLuint', 167 'int': 'GLint', 168 'unorm': 'GLfloat', 169 'snorm': 'GLfloat', 170 'float': 'GLfloat' 171 } 172 return component_type_map[angle_format['componentType']] 173 174 175def get_color_read_function(angle_format): 176 channel_struct = get_channel_struct(angle_format) 177 if channel_struct == None: 178 return 'nullptr' 179 180 if is_depth_stencil(angle_format): 181 return 'ReadDepthStencil<' + channel_struct + '>' 182 183 read_component_type = get_color_read_write_component_type(angle_format) 184 return 'ReadColor<' + channel_struct + ', ' + read_component_type + '>' 185 186 187def get_color_write_function(angle_format): 188 channel_struct = get_channel_struct(angle_format) 189 if channel_struct == None: 190 return 'nullptr' 191 192 if is_depth_stencil(angle_format): 193 return 'WriteDepthStencil<' + channel_struct + '>' 194 195 write_component_type = get_color_read_write_component_type(angle_format) 196 return 'WriteColor<' + channel_struct + ', ' + write_component_type + '>' 197 198 199format_entry_template = """ {{ FormatID::{id}, {glInternalFormat}, {fboImplementationInternalFormat}, {mipGenerationFunction}, {fastCopyFunctions}, {colorReadFunction}, {colorWriteFunction}, {namedComponentType}, {R}, {G}, {B}, {A}, {L}, {D}, {S}, {pixelBytes}, {componentAlignmentMask}, {isBlock}, {isFixed}, {isScaled}, {isSRGB}, {isYUV}, {vertexAttribType} }}, 200""" 201 202 203def get_named_component_type(component_type): 204 if component_type == "snorm": 205 return "GL_SIGNED_NORMALIZED" 206 elif component_type == "unorm": 207 return "GL_UNSIGNED_NORMALIZED" 208 elif component_type == "float": 209 return "GL_FLOAT" 210 elif component_type == "uint": 211 return "GL_UNSIGNED_INT" 212 elif component_type == "int": 213 return "GL_INT" 214 elif component_type == "none": 215 return "GL_NONE" 216 else: 217 raise ValueError("Unknown component type for " + component_type) 218 219 220def get_component_alignment_mask(channels, bits): 221 if channels == None or bits == None: 222 return "std::numeric_limits<GLuint>::max()" 223 bitness = bits[channels[0].upper()] 224 for channel in channels: 225 if channel not in "rgba": 226 return "std::numeric_limits<GLuint>::max()" 227 # Can happen for RGB10A2 formats. 228 if bits[channel.upper()] != bitness: 229 return "std::numeric_limits<GLuint>::max()" 230 component_bytes = (int(bitness) >> 3) 231 232 if component_bytes == 1: 233 return "0" 234 elif component_bytes == 2: 235 return "1" 236 elif component_bytes == 4: 237 return "3" 238 else: 239 # Can happen for 4-bit RGBA. 240 return "std::numeric_limits<GLuint>::max()" 241 242 243def get_vertex_attrib_type(format_id): 244 245 has_u = "_U" in format_id 246 has_s = "_S" in format_id 247 has_float = "_FLOAT" in format_id 248 has_fixed = "_FIXED" in format_id 249 has_r8 = "R8" in format_id 250 has_r16 = "R16" in format_id 251 has_r32 = "R32" in format_id 252 has_r10 = "R10" in format_id 253 has_vertex = "VERTEX" in format_id 254 255 if has_fixed: 256 return "Fixed" 257 258 if has_float: 259 return "HalfFloat" if has_r16 else "Float" 260 261 if has_r8: 262 return "Byte" if has_s else "UnsignedByte" 263 264 if has_r10: 265 if has_vertex: 266 return "Int1010102" if has_s else "UnsignedInt1010102" 267 else: 268 return "Int2101010" if has_s else "UnsignedInt2101010" 269 270 if has_r16: 271 return "Short" if has_s else "UnsignedShort" 272 273 if has_r32: 274 return "Int" if has_s else "UnsignedInt" 275 276 # Many ANGLE formats don't correspond with vertex formats. 277 return "InvalidEnum" 278 279 280def bool_str(cond): 281 return "true" if cond else "false" 282 283 284def json_to_table_data(format_id, json, angle_to_gl): 285 286 table_data = "" 287 288 parsed = { 289 "id": format_id, 290 "fastCopyFunctions": "NoCopyFunctions", 291 } 292 293 for k, v in sorted(json.items()): 294 parsed[k] = v 295 296 if "glInternalFormat" not in parsed: 297 parsed["glInternalFormat"] = angle_to_gl[format_id] 298 299 if "fboImplementationInternalFormat" not in parsed: 300 parsed["fboImplementationInternalFormat"] = parsed["glInternalFormat"] 301 302 if "componentType" not in parsed: 303 parsed["componentType"] = angle_format.get_component_type(format_id) 304 305 if "channels" not in parsed: 306 parsed["channels"] = angle_format.get_channels(format_id) 307 308 if "bits" not in parsed: 309 parsed["bits"] = angle_format.get_bits(format_id) 310 311 # Derived values. 312 parsed["mipGenerationFunction"] = get_mip_generation_function(parsed) 313 parsed["colorReadFunction"] = get_color_read_function(parsed) 314 parsed["colorWriteFunction"] = get_color_write_function(parsed) 315 316 for channel in angle_format.kChannels: 317 if parsed["bits"] != None and channel in parsed["bits"]: 318 parsed[channel] = parsed["bits"][channel] 319 else: 320 parsed[channel] = "0" 321 322 parsed["namedComponentType"] = get_named_component_type(parsed["componentType"]) 323 324 if format_id == "B8G8R8A8_UNORM": 325 parsed["fastCopyFunctions"] = "BGRACopyFunctions" 326 327 is_block = format_id.endswith("_BLOCK") 328 329 pixel_bytes = 0 330 if is_block: 331 assert 'blockPixelBytes' in parsed, \ 332 'Compressed format %s requires its block size to be specified in angle_format_data.json' % \ 333 format_id 334 pixel_bytes = parsed['blockPixelBytes'] 335 else: 336 sum_of_bits = 0 337 for channel in angle_format.kChannels: 338 sum_of_bits += int(parsed[channel]) 339 pixel_bytes = ceil_int(sum_of_bits, 8) 340 parsed["pixelBytes"] = pixel_bytes 341 parsed["componentAlignmentMask"] = get_component_alignment_mask(parsed["channels"], 342 parsed["bits"]) 343 parsed["isBlock"] = bool_str(is_block) 344 parsed["isFixed"] = bool_str("FIXED" in format_id) 345 parsed["isScaled"] = bool_str("SCALED" in format_id) 346 parsed["isSRGB"] = bool_str("SRGB" in format_id) 347 # For now we only look for the 'PLANE' or 'EXTERNAL' substring in format string. Expand this condition 348 # when adding support for YUV formats that have different identifying markers. 349 parsed["isYUV"] = bool_str("PLANE" in format_id or "EXTERNAL" in format_id) 350 351 parsed["vertexAttribType"] = "gl::VertexAttribType::" + get_vertex_attrib_type(format_id) 352 353 return format_entry_template.format(**parsed) 354 355 356# For convenience of the Vulkan backend, place depth/stencil formats first. This allows 357# depth/stencil format IDs to be placed in only a few bits. 358def sorted_ds_first(all_angle): 359 ds_sorted = [] 360 color_sorted = [] 361 external_sorted = [] 362 for format_id in sorted(all_angle): 363 if format_id == 'NONE': 364 continue 365 if 'EXTERNAL' in format_id: 366 external_sorted.append(format_id) 367 elif format_id[0] == 'D' or format_id[0] == 'S': 368 ds_sorted.append(format_id) 369 else: 370 color_sorted.append(format_id) 371 372 return ds_sorted + color_sorted + external_sorted 373 374 375def parse_angle_format_table(all_angle, json_data, angle_to_gl): 376 table_data = '' 377 for format_id in sorted_ds_first(all_angle): 378 assert (format_id != 'NONE') 379 format_info = json_data[format_id] if format_id in json_data else {} 380 table_data += json_to_table_data(format_id, format_info, angle_to_gl) 381 382 return table_data 383 384 385def gen_enum_string(all_angle): 386 enum_data = ' NONE' 387 for format_id in sorted_ds_first(all_angle): 388 assert (format_id != 'NONE') 389 enum_data += ',\n ' + format_id 390 return enum_data 391 392 393case_template = """ case {gl_format}: 394 return FormatID::{angle_format}; 395""" 396 397 398def gen_map_switch_string(gl_to_angle): 399 switch_data = '' 400 for gl_format in sorted(gl_to_angle.keys()): 401 angle_format = gl_to_angle[gl_format] 402 switch_data += case_template.format(gl_format=gl_format, angle_format=angle_format) 403 switch_data += " default:\n" 404 switch_data += " return FormatID::NONE;" 405 return switch_data 406 407 408def main(): 409 410 # auto_script parameters. 411 if len(sys.argv) > 1: 412 inputs = ['angle_format.py', 'angle_format_data.json', 'angle_format_map.json'] 413 outputs = ['Format_table_autogen.cpp', 'FormatID_autogen.h'] 414 415 if sys.argv[1] == 'inputs': 416 print(','.join(inputs)) 417 elif sys.argv[1] == 'outputs': 418 print(','.join(outputs)) 419 else: 420 print('Invalid script parameters') 421 return 1 422 return 0 423 424 gl_to_angle = angle_format.load_forward_table('angle_format_map.json') 425 angle_to_gl = angle_format.load_inverse_table('angle_format_map.json') 426 data_source_name = 'angle_format_data.json' 427 json_data = angle_format.load_json(data_source_name) 428 all_angle = angle_to_gl.keys() 429 430 angle_format_cases = parse_angle_format_table(all_angle, json_data, angle_to_gl) 431 switch_data = gen_map_switch_string(gl_to_angle) 432 output_cpp = template_autogen_inl.format( 433 script_name=os.path.basename(sys.argv[0]), 434 angle_format_info_cases=angle_format_cases, 435 angle_format_switch=switch_data, 436 data_source_name=data_source_name) 437 with open('Format_table_autogen.cpp', 'wt') as out_file: 438 out_file.write(output_cpp) 439 out_file.close() 440 441 enum_data = gen_enum_string(all_angle) 442 num_angle_formats = len(all_angle) 443 output_h = template_autogen_h.format( 444 script_name=os.path.basename(sys.argv[0]), 445 angle_format_enum=enum_data, 446 data_source_name=data_source_name, 447 num_angle_formats=num_angle_formats) 448 with open('FormatID_autogen.h', 'wt') as out_file: 449 out_file.write(output_h) 450 out_file.close() 451 452 return 0 453 454 455if __name__ == '__main__': 456 sys.exit(main()) 457