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