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#include "libANGLE/cl_types.h" 60 61#include "image_util/copyimage.h" 62#include "image_util/generatemip.h" 63#include "image_util/loadimage.h" 64 65namespace angle 66{{ 67 68static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {{angle::FormatID::R8G8B8A8_UNORM, 69 CopyBGRA8ToRGBA8}}; 70static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {{&BGRAEntry, 1}}; 71static constexpr rx::FastCopyFunctionMap NoCopyFunctions; 72 73const Format gFormatInfoTable[] = {{ 74 // clang-format off 75 {{ 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 }}, 76{angle_format_info_cases} // clang-format on 77}}; 78 79// static 80FormatID Format::InternalFormatToID(GLenum internalFormat) 81{{ 82 switch (internalFormat) 83 {{ 84{angle_format_switch} 85 }} 86}} 87 88#if defined(ANGLE_ENABLE_CL) 89// static 90FormatID Format::CLRFormatToID(cl_channel_type internalChannelType) 91{{ 92 switch (internalChannelType) 93 {{ 94{angle_r_format_switch} 95 }} 96}} 97 98// static 99FormatID Format::CLRGFormatToID(cl_channel_type internalChannelType) 100{{ 101 switch (internalChannelType) 102 {{ 103{angle_rg_format_switch} 104 }} 105}} 106 107// static 108FormatID Format::CLRGBFormatToID(cl_channel_type internalChannelType) 109{{ 110 switch (internalChannelType) 111 {{ 112{angle_rgb_format_switch} 113 }} 114}} 115 116// static 117FormatID Format::CLRGBAFormatToID(cl_channel_type internalChannelType) 118{{ 119 switch (internalChannelType) 120 {{ 121{angle_rgba_format_switch} 122 }} 123}} 124 125// static 126FormatID Format::CLBGRAFormatToID(cl_channel_type internalChannelType) 127{{ 128 switch (internalChannelType) 129 {{ 130{angle_bgra_format_switch} 131 }} 132}} 133 134// static 135FormatID Format::CLsRGBAFormatToID(cl_channel_type internalChannelType) 136{{ 137 switch (internalChannelType) 138 {{ 139{angle_srgba_format_switch} 140 }} 141}} 142 143// static 144FormatID Format::CLDEPTHFormatToID(cl_channel_type internalChannelType) 145{{ 146 switch (internalChannelType) 147 {{ 148{angle_depth_format_switch} 149 }} 150}} 151 152// static 153FormatID Format::CLDEPTHSTENCILFormatToID(cl_channel_type internalChannelType) 154{{ 155 switch (internalChannelType) 156 {{ 157{angle_depth_stencil_format_switch} 158 }} 159}} 160#endif // ANGLE_ENABLE_CL 161 162const Format *GetFormatInfoTable() 163{{ 164 return gFormatInfoTable; 165}} 166}} // namespace angle 167""" 168 169 170def ceil_int(value, mod): 171 assert mod > 0 and value > 0, 'integer modulation should be larger than 0' 172 return (value + mod - 1) // mod 173 174 175def is_depth_stencil(angle_format): 176 if not 'channels' in angle_format or not angle_format['channels']: 177 return False 178 return 'd' in angle_format['channels'] or 's' in angle_format['channels'] 179 180 181def get_component_suffix(angle_format): 182 if angle_format['componentType'] == 'float': 183 return 'F' 184 if angle_format['componentType'] == 'int' or angle_format['componentType'] == 'snorm': 185 return 'S' 186 return "" 187 188 189def get_channel_struct(angle_format): 190 if 'bits' not in angle_format or angle_format['bits'] is None: 191 return None 192 if 'BLOCK' in angle_format['id']: 193 return None 194 if 'VERTEX' in angle_format['id']: 195 return None 196 if 'EXTERNAL' in angle_format['id']: 197 return None 198 199 bits = angle_format['bits'] 200 201 if 'channelStruct' in angle_format: 202 return angle_format['channelStruct'] 203 204 struct_name = '' 205 component_suffix = get_component_suffix(angle_format) 206 207 for channel in angle_format['channels']: 208 if channel == 'r': 209 struct_name += 'R{}'.format(bits['R']) 210 if channel == 'g': 211 struct_name += 'G{}'.format(bits['G']) 212 if channel == 'b': 213 struct_name += 'B{}'.format(bits['B']) 214 if channel == 'a': 215 struct_name += 'A{}'.format(bits['A']) 216 if channel == 'l': 217 struct_name += 'L{}'.format(bits['L']) 218 if channel == 'd': 219 struct_name += 'D{}'.format(bits['D']) + component_suffix 220 if channel == 's': 221 struct_name += 'S{}'.format(bits['S']) 222 if channel == 'x': 223 struct_name += 'X{}'.format(bits['X']) 224 225 if not is_depth_stencil(angle_format): 226 struct_name += component_suffix 227 228 return struct_name 229 230 231def get_mip_generation_function(angle_format): 232 channel_struct = get_channel_struct(angle_format) 233 if is_depth_stencil(angle_format) or channel_struct == None \ 234 or "BLOCK" in angle_format["id"] or "VERTEX" in angle_format["id"]: 235 return 'nullptr' 236 return 'GenerateMip<' + channel_struct + '>' 237 238 239def get_color_read_write_component_type(angle_format): 240 component_type_map = { 241 'uint': 'GLuint', 242 'int': 'GLint', 243 'unorm': 'GLfloat', 244 'snorm': 'GLfloat', 245 'float': 'GLfloat' 246 } 247 return component_type_map[angle_format['componentType']] 248 249 250def get_color_read_function(angle_format): 251 channel_struct = get_channel_struct(angle_format) 252 if channel_struct == None: 253 return 'nullptr' 254 255 if is_depth_stencil(angle_format): 256 return 'ReadDepthStencil<' + channel_struct + '>' 257 258 read_component_type = get_color_read_write_component_type(angle_format) 259 return 'ReadColor<' + channel_struct + ', ' + read_component_type + '>' 260 261 262def get_color_write_function(angle_format): 263 channel_struct = get_channel_struct(angle_format) 264 if channel_struct == None: 265 return 'nullptr' 266 267 if is_depth_stencil(angle_format): 268 return 'WriteDepthStencil<' + channel_struct + '>' 269 270 write_component_type = get_color_read_write_component_type(angle_format) 271 return 'WriteColor<' + channel_struct + ', ' + write_component_type + '>' 272 273 274format_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} }}, 275""" 276 277 278def get_named_component_type(component_type): 279 if component_type == "snorm": 280 return "GL_SIGNED_NORMALIZED" 281 elif component_type == "unorm": 282 return "GL_UNSIGNED_NORMALIZED" 283 elif component_type == "float": 284 return "GL_FLOAT" 285 elif component_type == "uint": 286 return "GL_UNSIGNED_INT" 287 elif component_type == "int": 288 return "GL_INT" 289 elif component_type == "none": 290 return "GL_NONE" 291 else: 292 raise ValueError("Unknown component type for " + component_type) 293 294 295def get_component_alignment_mask(channels, bits): 296 if channels == None or bits == None: 297 return "std::numeric_limits<GLuint>::max()" 298 bitness = bits[channels[0].upper()] 299 for channel in channels: 300 if channel not in "rgba": 301 return "std::numeric_limits<GLuint>::max()" 302 # Can happen for RGB10A2 formats. 303 if bits[channel.upper()] != bitness: 304 return "std::numeric_limits<GLuint>::max()" 305 component_bytes = (int(bitness) >> 3) 306 307 if component_bytes == 1: 308 return "0" 309 elif component_bytes == 2: 310 return "1" 311 elif component_bytes == 4: 312 return "3" 313 else: 314 # Can happen for 4-bit RGBA. 315 return "std::numeric_limits<GLuint>::max()" 316 317 318def get_vertex_attrib_type(format_id): 319 320 has_u = "_U" in format_id 321 has_s = "_S" in format_id 322 has_float = "_FLOAT" in format_id 323 has_fixed = "_FIXED" in format_id 324 has_r8 = "R8" in format_id 325 has_r16 = "R16" in format_id 326 has_r32 = "R32" in format_id 327 has_r10 = "R10" in format_id 328 has_vertex = "VERTEX" in format_id 329 330 if has_fixed: 331 return "Fixed" 332 333 if has_float: 334 return "HalfFloat" if has_r16 else "Float" 335 336 if has_r8: 337 return "Byte" if has_s else "UnsignedByte" 338 339 if has_r10: 340 if has_vertex: 341 return "Int1010102" if has_s else "UnsignedInt1010102" 342 else: 343 return "Int2101010" if has_s else "UnsignedInt2101010" 344 345 if has_r16: 346 return "Short" if has_s else "UnsignedShort" 347 348 if has_r32: 349 return "Int" if has_s else "UnsignedInt" 350 351 # Many ANGLE formats don't correspond with vertex formats. 352 return "InvalidEnum" 353 354 355def bool_str(cond): 356 return "true" if cond else "false" 357 358 359def json_to_table_data(format_id, json, angle_to_gl): 360 361 table_data = "" 362 363 parsed = { 364 "id": format_id, 365 "fastCopyFunctions": "NoCopyFunctions", 366 } 367 368 for k, v in sorted(json.items()): 369 parsed[k] = v 370 371 if "glInternalFormat" not in parsed: 372 parsed["glInternalFormat"] = angle_to_gl[format_id] 373 374 if "fboImplementationInternalFormat" not in parsed: 375 parsed["fboImplementationInternalFormat"] = parsed["glInternalFormat"] 376 377 if "componentType" not in parsed: 378 parsed["componentType"] = angle_format.get_component_type(format_id) 379 380 if "channels" not in parsed: 381 parsed["channels"] = angle_format.get_channels(format_id) 382 383 if "bits" not in parsed: 384 parsed["bits"] = angle_format.get_bits(format_id) 385 386 # Derived values. 387 parsed["mipGenerationFunction"] = get_mip_generation_function(parsed) 388 parsed["colorReadFunction"] = get_color_read_function(parsed) 389 parsed["colorWriteFunction"] = get_color_write_function(parsed) 390 391 for channel in angle_format.kChannels: 392 if parsed["bits"] != None and channel in parsed["bits"]: 393 parsed[channel] = parsed["bits"][channel] 394 else: 395 parsed[channel] = "0" 396 397 parsed["namedComponentType"] = get_named_component_type(parsed["componentType"]) 398 399 if format_id == "B8G8R8A8_UNORM": 400 parsed["fastCopyFunctions"] = "BGRACopyFunctions" 401 402 is_block = format_id.endswith("_BLOCK") 403 404 pixel_bytes = 0 405 if is_block: 406 assert 'blockPixelBytes' in parsed, \ 407 'Compressed format %s requires its block size to be specified in angle_format_data.json' % \ 408 format_id 409 pixel_bytes = parsed['blockPixelBytes'] 410 else: 411 sum_of_bits = 0 412 for channel in angle_format.kChannels: 413 sum_of_bits += int(parsed[channel]) 414 pixel_bytes = ceil_int(sum_of_bits, 8) 415 parsed["pixelBytes"] = pixel_bytes 416 parsed["componentAlignmentMask"] = get_component_alignment_mask(parsed["channels"], 417 parsed["bits"]) 418 parsed["isBlock"] = bool_str(is_block) 419 parsed["isFixed"] = bool_str("FIXED" in format_id) 420 parsed["isScaled"] = bool_str("SCALED" in format_id) 421 parsed["isSRGB"] = bool_str("SRGB" in format_id) 422 # For now we only look for the 'PLANE' or 'EXTERNAL' substring in format string. Expand this condition 423 # when adding support for YUV formats that have different identifying markers. 424 parsed["isYUV"] = bool_str("PLANE" in format_id or "EXTERNAL" in format_id) 425 426 parsed["vertexAttribType"] = "gl::VertexAttribType::" + get_vertex_attrib_type(format_id) 427 428 return format_entry_template.format(**parsed) 429 430 431# For convenience of the Vulkan backend, place depth/stencil formats first. This allows 432# depth/stencil format IDs to be placed in only a few bits. 433def sorted_ds_first(all_angle): 434 ds_sorted = [] 435 color_sorted = [] 436 external_sorted = [] 437 for format_id in sorted(all_angle): 438 if format_id == 'NONE': 439 continue 440 if 'EXTERNAL' in format_id: 441 external_sorted.append(format_id) 442 elif format_id[0] == 'D' or format_id[0] == 'S': 443 ds_sorted.append(format_id) 444 else: 445 color_sorted.append(format_id) 446 447 return ds_sorted + color_sorted + external_sorted 448 449 450def parse_angle_format_table(all_angle, json_data, angle_to_gl): 451 table_data = '' 452 for format_id in sorted_ds_first(all_angle): 453 assert (format_id != 'NONE') 454 format_info = json_data[format_id] if format_id in json_data else {} 455 table_data += json_to_table_data(format_id, format_info, angle_to_gl) 456 457 return table_data 458 459 460def gen_enum_string(all_angle): 461 enum_data = ' NONE' 462 for format_id in sorted_ds_first(all_angle): 463 assert (format_id != 'NONE') 464 enum_data += ',\n ' + format_id 465 return enum_data 466 467 468case_template = """ case {gl_format}: 469 return FormatID::{angle_format}; 470""" 471 472 473def gen_map_switch_string(gl_to_angle): 474 switch_data = '' 475 for gl_format in sorted(gl_to_angle.keys()): 476 angle_format = gl_to_angle[gl_format] 477 switch_data += case_template.format(gl_format=gl_format, angle_format=angle_format) 478 switch_data += " default:\n" 479 switch_data += " return FormatID::NONE;" 480 return switch_data 481 482 483def main(): 484 485 # auto_script parameters. 486 if len(sys.argv) > 1: 487 inputs = ['angle_format.py', 'angle_format_data.json', 'angle_format_map.json'] 488 outputs = ['Format_table_autogen.cpp', 'FormatID_autogen.h'] 489 490 if sys.argv[1] == 'inputs': 491 print(','.join(inputs)) 492 elif sys.argv[1] == 'outputs': 493 print(','.join(outputs)) 494 else: 495 print('Invalid script parameters') 496 return 1 497 return 0 498 499 gl_to_angle = angle_format.load_forward_table('angle_format_map.json') 500 501 cl_r_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "r") 502 cl_rg_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rg") 503 cl_rgb_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rgb") 504 cl_rgba_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rgba") 505 cl_bgra_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "bgra") 506 cl_srgba_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "srgba") 507 cl_depth_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "depth") 508 cl_depth_stencil_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', 509 "depth_stencil") 510 511 angle_to_gl = angle_format.load_inverse_table('angle_format_map.json') 512 data_source_name = 'angle_format_data.json' 513 json_data = angle_format.load_json(data_source_name) 514 all_angle = angle_to_gl.keys() 515 516 angle_format_cases = parse_angle_format_table(all_angle, json_data, angle_to_gl) 517 switch_data = gen_map_switch_string(gl_to_angle) 518 519 cl_r_switch_data = gen_map_switch_string(cl_r_to_angle) 520 cl_rg_switch_data = gen_map_switch_string(cl_rg_to_angle) 521 cl_rgb_switch_data = gen_map_switch_string(cl_rgb_to_angle) 522 cl_rgba_switch_data = gen_map_switch_string(cl_rgba_to_angle) 523 cl_bgra_switch_data = gen_map_switch_string(cl_bgra_to_angle) 524 cl_srgba_switch_data = gen_map_switch_string(cl_srgba_to_angle) 525 cl_depth_switch_data = gen_map_switch_string(cl_depth_to_angle) 526 cl_depth_stencil_switch_data = gen_map_switch_string(cl_depth_stencil_to_angle) 527 528 output_cpp = template_autogen_inl.format( 529 script_name=os.path.basename(sys.argv[0]), 530 angle_format_info_cases=angle_format_cases, 531 angle_format_switch=switch_data, 532 data_source_name=data_source_name, 533 angle_r_format_switch=cl_r_switch_data, 534 angle_rg_format_switch=cl_rg_switch_data, 535 angle_rgb_format_switch=cl_rgb_switch_data, 536 angle_rgba_format_switch=cl_rgba_switch_data, 537 angle_bgra_format_switch=cl_bgra_switch_data, 538 angle_srgba_format_switch=cl_srgba_switch_data, 539 angle_depth_format_switch=cl_depth_switch_data, 540 angle_depth_stencil_format_switch=cl_depth_stencil_switch_data) 541 542 with open('Format_table_autogen.cpp', 'wt') as out_file: 543 out_file.write(output_cpp) 544 out_file.close() 545 546 enum_data = gen_enum_string(all_angle) 547 num_angle_formats = len(all_angle) 548 output_h = template_autogen_h.format( 549 script_name=os.path.basename(sys.argv[0]), 550 angle_format_enum=enum_data, 551 data_source_name=data_source_name, 552 num_angle_formats=num_angle_formats) 553 with open('FormatID_autogen.h', 'wt') as out_file: 554 out_file.write(output_h) 555 out_file.close() 556 557 return 0 558 559 560if __name__ == '__main__': 561 sys.exit(main()) 562