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 122 bits = angle_format['bits'] 123 124 if 'channelStruct' in angle_format: 125 return angle_format['channelStruct'] 126 127 struct_name = '' 128 component_suffix = get_component_suffix(angle_format) 129 130 for channel in angle_format['channels']: 131 if channel == 'r': 132 struct_name += 'R{}'.format(bits['R']) 133 if channel == 'g': 134 struct_name += 'G{}'.format(bits['G']) 135 if channel == 'b': 136 struct_name += 'B{}'.format(bits['B']) 137 if channel == 'a': 138 struct_name += 'A{}'.format(bits['A']) 139 if channel == 'l': 140 struct_name += 'L{}'.format(bits['L']) 141 if channel == 'd': 142 struct_name += 'D{}'.format(bits['D']) + component_suffix 143 if channel == 's': 144 struct_name += 'S{}'.format(bits['S']) 145 if channel == 'x': 146 struct_name += 'X{}'.format(bits['X']) 147 148 if not is_depth_stencil(angle_format): 149 struct_name += component_suffix 150 151 return struct_name 152 153 154def get_mip_generation_function(angle_format): 155 channel_struct = get_channel_struct(angle_format) 156 if is_depth_stencil(angle_format) or channel_struct == None \ 157 or "BLOCK" in angle_format["id"] or "VERTEX" in angle_format["id"]: 158 return 'nullptr' 159 return 'GenerateMip<' + channel_struct + '>' 160 161 162def get_color_read_write_component_type(angle_format): 163 component_type_map = { 164 'uint': 'GLuint', 165 'int': 'GLint', 166 'unorm': 'GLfloat', 167 'snorm': 'GLfloat', 168 'float': 'GLfloat' 169 } 170 return component_type_map[angle_format['componentType']] 171 172 173def get_color_read_function(angle_format): 174 channel_struct = get_channel_struct(angle_format) 175 if channel_struct == None: 176 return 'nullptr' 177 178 if is_depth_stencil(angle_format): 179 return 'ReadDepthStencil<' + channel_struct + '>' 180 181 read_component_type = get_color_read_write_component_type(angle_format) 182 return 'ReadColor<' + channel_struct + ', ' + read_component_type + '>' 183 184 185def get_color_write_function(angle_format): 186 channel_struct = get_channel_struct(angle_format) 187 if channel_struct == None: 188 return 'nullptr' 189 190 if is_depth_stencil(angle_format): 191 return 'WriteDepthStencil<' + channel_struct + '>' 192 193 write_component_type = get_color_read_write_component_type(angle_format) 194 return 'WriteColor<' + channel_struct + ', ' + write_component_type + '>' 195 196 197format_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} }}, 198""" 199 200 201def get_named_component_type(component_type): 202 if component_type == "snorm": 203 return "GL_SIGNED_NORMALIZED" 204 elif component_type == "unorm": 205 return "GL_UNSIGNED_NORMALIZED" 206 elif component_type == "float": 207 return "GL_FLOAT" 208 elif component_type == "uint": 209 return "GL_UNSIGNED_INT" 210 elif component_type == "int": 211 return "GL_INT" 212 elif component_type == "none": 213 return "GL_NONE" 214 else: 215 raise ValueError("Unknown component type for " + component_type) 216 217 218def get_component_alignment_mask(channels, bits): 219 if channels == None or bits == None: 220 return "std::numeric_limits<GLuint>::max()" 221 bitness = bits[channels[0].upper()] 222 for channel in channels: 223 if channel not in "rgba": 224 return "std::numeric_limits<GLuint>::max()" 225 # Can happen for RGB10A2 formats. 226 if bits[channel.upper()] != bitness: 227 return "std::numeric_limits<GLuint>::max()" 228 component_bytes = (int(bitness) >> 3) 229 230 if component_bytes == 1: 231 return "0" 232 elif component_bytes == 2: 233 return "1" 234 elif component_bytes == 4: 235 return "3" 236 else: 237 # Can happen for 4-bit RGBA. 238 return "std::numeric_limits<GLuint>::max()" 239 240 241def get_vertex_attrib_type(format_id): 242 243 has_u = "_U" in format_id 244 has_s = "_S" in format_id 245 has_float = "_FLOAT" in format_id 246 has_fixed = "_FIXED" in format_id 247 has_r8 = "R8" in format_id 248 has_r16 = "R16" in format_id 249 has_r32 = "R32" in format_id 250 has_r10 = "R10" in format_id 251 has_vertex = "VERTEX" in format_id 252 253 if has_fixed: 254 return "Fixed" 255 256 if has_float: 257 return "HalfFloat" if has_r16 else "Float" 258 259 if has_r8: 260 return "Byte" if has_s else "UnsignedByte" 261 262 if has_r10: 263 if has_vertex: 264 return "Int1010102" if has_s else "UnsignedInt1010102" 265 else: 266 return "Int2101010" if has_s else "UnsignedInt2101010" 267 268 if has_r16: 269 return "Short" if has_s else "UnsignedShort" 270 271 if has_r32: 272 return "Int" if has_s else "UnsignedInt" 273 274 # Many ANGLE formats don't correspond with vertex formats. 275 return "InvalidEnum" 276 277 278def bool_str(cond): 279 return "true" if cond else "false" 280 281 282def json_to_table_data(format_id, json, angle_to_gl): 283 284 table_data = "" 285 286 parsed = { 287 "id": format_id, 288 "fastCopyFunctions": "NoCopyFunctions", 289 } 290 291 for k, v in sorted(json.items()): 292 parsed[k] = v 293 294 if "glInternalFormat" not in parsed: 295 parsed["glInternalFormat"] = angle_to_gl[format_id] 296 297 if "fboImplementationInternalFormat" not in parsed: 298 parsed["fboImplementationInternalFormat"] = parsed["glInternalFormat"] 299 300 if "componentType" not in parsed: 301 parsed["componentType"] = angle_format.get_component_type(format_id) 302 303 if "channels" not in parsed: 304 parsed["channels"] = angle_format.get_channels(format_id) 305 306 if "bits" not in parsed: 307 parsed["bits"] = angle_format.get_bits(format_id) 308 309 # Derived values. 310 parsed["mipGenerationFunction"] = get_mip_generation_function(parsed) 311 parsed["colorReadFunction"] = get_color_read_function(parsed) 312 parsed["colorWriteFunction"] = get_color_write_function(parsed) 313 314 for channel in angle_format.kChannels: 315 if parsed["bits"] != None and channel in parsed["bits"]: 316 parsed[channel] = parsed["bits"][channel] 317 else: 318 parsed[channel] = "0" 319 320 parsed["namedComponentType"] = get_named_component_type(parsed["componentType"]) 321 322 if format_id == "B8G8R8A8_UNORM": 323 parsed["fastCopyFunctions"] = "BGRACopyFunctions" 324 325 is_block = format_id.endswith("_BLOCK") 326 327 pixel_bytes = 0 328 if is_block: 329 assert 'blockPixelBytes' in parsed, \ 330 'Compressed format %s requires its block size to be specified in angle_format_data.json' % \ 331 format_id 332 pixel_bytes = parsed['blockPixelBytes'] 333 else: 334 sum_of_bits = 0 335 for channel in angle_format.kChannels: 336 sum_of_bits += int(parsed[channel]) 337 pixel_bytes = ceil_int(sum_of_bits, 8) 338 parsed["pixelBytes"] = pixel_bytes 339 parsed["componentAlignmentMask"] = get_component_alignment_mask(parsed["channels"], 340 parsed["bits"]) 341 parsed["isBlock"] = bool_str(is_block) 342 parsed["isFixed"] = bool_str("FIXED" in format_id) 343 parsed["isScaled"] = bool_str("SCALED" in format_id) 344 parsed["isSRGB"] = bool_str("SRGB" in format_id) 345 # For now we only look for the 'PLANE' substring in format string. Expand this condition 346 # when adding support for YUV formats that have different identifying markers. 347 parsed["isYUV"] = bool_str("PLANE" in format_id) 348 349 parsed["vertexAttribType"] = "gl::VertexAttribType::" + get_vertex_attrib_type(format_id) 350 351 return format_entry_template.format(**parsed) 352 353 354# For convenience of the Vulkan backend, place depth/stencil formats first. This allows 355# depth/stencil format IDs to be placed in only a few bits. 356def sorted_ds_first(all_angle): 357 ds_sorted = [] 358 color_sorted = [] 359 for format_id in sorted(all_angle): 360 if format_id == 'NONE': 361 continue 362 if format_id[0] == 'D' or format_id[0] == 'S': 363 ds_sorted.append(format_id) 364 else: 365 color_sorted.append(format_id) 366 367 return ds_sorted + color_sorted 368 369 370def parse_angle_format_table(all_angle, json_data, angle_to_gl): 371 table_data = '' 372 for format_id in sorted_ds_first(all_angle): 373 assert (format_id != 'NONE') 374 format_info = json_data[format_id] if format_id in json_data else {} 375 table_data += json_to_table_data(format_id, format_info, angle_to_gl) 376 377 return table_data 378 379 380def gen_enum_string(all_angle): 381 enum_data = ' NONE' 382 for format_id in sorted_ds_first(all_angle): 383 assert (format_id != 'NONE') 384 enum_data += ',\n ' + format_id 385 return enum_data 386 387 388case_template = """ case {gl_format}: 389 return FormatID::{angle_format}; 390""" 391 392 393def gen_map_switch_string(gl_to_angle): 394 switch_data = '' 395 for gl_format in sorted(gl_to_angle.keys()): 396 angle_format = gl_to_angle[gl_format] 397 switch_data += case_template.format(gl_format=gl_format, angle_format=angle_format) 398 switch_data += " default:\n" 399 switch_data += " return FormatID::NONE;" 400 return switch_data 401 402 403def main(): 404 405 # auto_script parameters. 406 if len(sys.argv) > 1: 407 inputs = ['angle_format.py', 'angle_format_data.json', 'angle_format_map.json'] 408 outputs = ['Format_table_autogen.cpp', 'FormatID_autogen.h'] 409 410 if sys.argv[1] == 'inputs': 411 print(','.join(inputs)) 412 elif sys.argv[1] == 'outputs': 413 print(','.join(outputs)) 414 else: 415 print('Invalid script parameters') 416 return 1 417 return 0 418 419 gl_to_angle = angle_format.load_forward_table('angle_format_map.json') 420 angle_to_gl = angle_format.load_inverse_table('angle_format_map.json') 421 data_source_name = 'angle_format_data.json' 422 json_data = angle_format.load_json(data_source_name) 423 all_angle = angle_to_gl.keys() 424 425 angle_format_cases = parse_angle_format_table(all_angle, json_data, angle_to_gl) 426 switch_data = gen_map_switch_string(gl_to_angle) 427 output_cpp = template_autogen_inl.format( 428 script_name=os.path.basename(sys.argv[0]), 429 angle_format_info_cases=angle_format_cases, 430 angle_format_switch=switch_data, 431 data_source_name=data_source_name) 432 with open('Format_table_autogen.cpp', 'wt') as out_file: 433 out_file.write(output_cpp) 434 out_file.close() 435 436 enum_data = gen_enum_string(all_angle) 437 num_angle_formats = len(all_angle) 438 output_h = template_autogen_h.format( 439 script_name=os.path.basename(sys.argv[0]), 440 angle_format_enum=enum_data, 441 data_source_name=data_source_name, 442 num_angle_formats=num_angle_formats) 443 with open('FormatID_autogen.h', 'wt') as out_file: 444 out_file.write(output_h) 445 out_file.close() 446 447 return 0 448 449 450if __name__ == '__main__': 451 sys.exit(main()) 452