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