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# angle_format.py: 7# Utils for ANGLE formats. 8 9import json 10import os 11import re 12 13kChannels = "ABDEGLRSX" 14 15 16def get_angle_format_map_abs_path(): 17 return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'angle_format_map.json') 18 19 20def reject_duplicate_keys(pairs): 21 found_keys = {} 22 for key, value in pairs: 23 if key in found_keys: 24 raise ValueError("duplicate key: %r" % (key,)) 25 else: 26 found_keys[key] = value 27 return found_keys 28 29 30def load_json(path): 31 with open(path) as map_file: 32 return json.loads(map_file.read(), object_pairs_hook=reject_duplicate_keys) 33 34 35def load_forward_table(path, key=None): 36 pairs = load_json(path) 37 if key is not None: 38 pairs = pairs[key] 39 reject_duplicate_keys(pairs) 40 return {gl: angle for gl, angle in pairs} 41 42 43def load_inverse_table(path): 44 pairs = load_json(path) 45 reject_duplicate_keys(pairs) 46 for x in range(0, 8): 47 pairs.append(("GL_NONE", "EXTERNAL" + str(x))) 48 return {angle: gl for gl, angle in pairs} 49 50 51def load_without_override(): 52 map_path = get_angle_format_map_abs_path() 53 return load_forward_table(map_path) 54 55 56def load_with_override(override_path): 57 results = load_without_override() 58 overrides = load_json(override_path) 59 60 for k, v in sorted(overrides.items()): 61 results[k] = v 62 63 return results 64 65 66def get_all_angle_formats(): 67 map_path = get_angle_format_map_abs_path() 68 return load_inverse_table(map_path).keys() 69 70 71def get_component_type(format_id): 72 if "SNORM" in format_id: 73 return "snorm" 74 elif "UNORM" in format_id: 75 return "unorm" 76 elif "FLOAT" in format_id: 77 return "float" 78 elif "FIXED" in format_id: 79 return "float" 80 elif "UINT" in format_id: 81 return "uint" 82 elif "SINT" in format_id: 83 return "int" 84 elif "USCALED" in format_id: 85 return "uint" 86 elif "SSCALED" in format_id: 87 return "int" 88 elif format_id == "NONE": 89 return "none" 90 elif "SRGB" in format_id: 91 return "unorm" 92 elif "TYPELESS" in format_id: 93 return "unorm" 94 elif "EXTERNAL" in format_id: 95 return "unorm" 96 elif format_id == "R9G9B9E5_SHAREDEXP": 97 return "float" 98 else: 99 raise ValueError("Unknown component type for " + format_id) 100 101 102def get_channel_tokens(format_id): 103 if 'EXTERNAL' in format_id: 104 return ['R8', 'G8', 'B8', 'A8'] 105 r = re.compile(r'([' + kChannels + '][\d]+)') 106 return list(filter(r.match, r.split(format_id))) 107 108 109def get_channels(format_id): 110 channels = '' 111 tokens = get_channel_tokens(format_id) 112 if len(tokens) == 0: 113 return None 114 for token in tokens: 115 channels += token[0].lower() 116 117 return channels 118 119 120def get_bits(format_id): 121 bits = {} 122 if "_RED_" in format_id: 123 # BC4 124 bits["R"] = 16 125 elif "_RG_" in format_id: 126 # BC5 127 bits["R"] = bits["G"] = 16 128 elif "_RGB_" in format_id: 129 # BC1-3, BC6H, PVRTC 130 bits["R"] = bits["G"] = bits["B"] = 16 if "BC6H" in format_id else 8 131 elif "_RGBA_" in format_id or "ASTC_" in format_id: 132 # ASTC, BC7, PVRTC 133 bits["R"] = bits["G"] = bits["B"] = bits["A"] = 8 134 else: 135 tokens = get_channel_tokens(format_id) 136 for token in tokens: 137 bits[token[0]] = int(token[1:]) 138 return bits 139 140 141def get_format_info(format_id): 142 return get_component_type(format_id), get_bits(format_id), get_channels(format_id) 143 144 145# TODO(oetuaho): Expand this code so that it could generate the gl format info tables as well. 146def gl_format_channels(internal_format): 147 if internal_format == 'GL_BGR5_A1_ANGLEX': 148 return 'bgra' 149 if internal_format == 'GL_R11F_G11F_B10F': 150 return 'rgb' 151 if internal_format == 'GL_RGB5_A1': 152 return 'rgba' 153 if internal_format.find('GL_RGB10_A2') == 0: 154 return 'rgba' 155 if internal_format.find('GL_RGB10') == 0: 156 return 'rgb' 157 # signed/unsigned int_10_10_10_2 for vertex format 158 if internal_format.find('INT_10_10_10_2_OES') == 0: 159 return 'rgba' 160 161 channels_pattern = re.compile('GL_(COMPRESSED_)?(SIGNED_)?(ETC\d_)?([A-Z]+)') 162 match = re.search(channels_pattern, internal_format) 163 channels_string = match.group(4) 164 165 if channels_string == 'ALPHA': 166 return 'a' 167 if channels_string == 'LUMINANCE': 168 if (internal_format.find('ALPHA') >= 0): 169 return 'la' 170 return 'l' 171 if channels_string == 'SRGB' or channels_string == 'RGB': 172 if (internal_format.find('ALPHA') >= 0): 173 return 'rgba' 174 return 'rgb' 175 if channels_string == 'DEPTH': 176 if (internal_format.find('STENCIL') >= 0): 177 return 'ds' 178 return 'd' 179 if channels_string == 'STENCIL': 180 return 's' 181 return channels_string.lower() 182 183 184def get_internal_format_initializer(internal_format, format_id): 185 gl_channels = gl_format_channels(internal_format) 186 gl_format_no_alpha = gl_channels == 'rgb' or gl_channels == 'l' 187 component_type, bits, channels = get_format_info(format_id) 188 189 # ETC2 punchthrough formats have per-pixel alpha values but a zero-filled block is parsed as opaque black. 190 # Ensure correct initialization when the formats are emulated. 191 if 'PUNCHTHROUGH_ALPHA1_ETC2' in internal_format and 'ETC2' not in format_id: 192 return 'Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>' 193 194 if not gl_format_no_alpha or channels != 'rgba': 195 return 'nullptr' 196 197 elif internal_format == 'GL_RGB10_EXT': 198 return 'nullptr' 199 200 elif 'BC1_' in format_id: 201 # BC1 is a special case since the texture data determines whether each block has an alpha channel or not. 202 # This if statement is hit by COMPRESSED_RGB_S3TC_DXT1, which is a bit of a mess. 203 # TODO(oetuaho): Look into whether COMPRESSED_RGB_S3TC_DXT1 works right in general. 204 # Reference: https://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt 205 return 'nullptr' 206 207 elif component_type == 'uint' and bits['R'] == 8: 208 return 'Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01>' 209 elif component_type == 'unorm' and bits['R'] == 8: 210 return 'Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>' 211 elif component_type == 'unorm' and bits['R'] == 16: 212 return 'Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0xFFFF>' 213 elif component_type == 'int' and bits['R'] == 8: 214 return 'Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01>' 215 elif component_type == 'snorm' and bits['R'] == 8: 216 return 'Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x7F>' 217 elif component_type == 'snorm' and bits['R'] == 16: 218 return 'Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x7FFF>' 219 elif component_type == 'float' and bits['R'] == 16: 220 return 'Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>' 221 elif component_type == 'uint' and bits['R'] == 16: 222 return 'Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001>' 223 elif component_type == 'int' and bits['R'] == 16: 224 return 'Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001>' 225 elif component_type == 'float' and bits['R'] == 32: 226 return 'Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>' 227 elif component_type == 'int' and bits['R'] == 32: 228 return 'Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000, 0x00000001>' 229 elif component_type == 'uint' and bits['R'] == 32: 230 return 'Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000, 0x00000001>' 231 else: 232 raise ValueError( 233 'warning: internal format initializer could not be generated and may be needed for ' + 234 internal_format) 235 236 237def get_format_gl_type(format): 238 sign = '' 239 base_type = None 240 if 'FLOAT' in format: 241 bits = get_bits(format) 242 redbits = bits and bits.get('R') 243 base_type = 'float' 244 if redbits == 16: 245 base_type = 'half' 246 else: 247 bits = get_bits(format) 248 redbits = bits and bits.get('R') 249 if redbits == 8: 250 base_type = 'byte' 251 elif redbits == 16: 252 base_type = 'short' 253 elif redbits == 32: 254 base_type = 'int' 255 256 if 'UINT' in format or 'UNORM' in format or 'USCALED' in format: 257 sign = 'u' 258 259 if base_type is None: 260 return None 261 262 return 'GL' + sign + base_type 263 264 265def get_vertex_copy_function(src_format, dst_format): 266 if dst_format == "NONE": 267 return "nullptr" 268 269 src_num_channel = len(get_channel_tokens(src_format)) 270 dst_num_channel = len(get_channel_tokens(dst_format)) 271 if src_num_channel < 1 or src_num_channel > 4: 272 return "nullptr" 273 274 if src_format.endswith('_VERTEX'): 275 is_signed = 'true' if 'SINT' in src_format or 'SNORM' in src_format or 'SSCALED' in src_format else 'false' 276 is_normal = 'true' if 'NORM' in src_format else 'false' 277 if 'A2' in src_format: 278 return 'CopyW2XYZ10ToXYZWFloatVertexData<%s, %s, true>' % (is_signed, is_normal) 279 else: 280 return 'CopyXYZ10ToXYZWFloatVertexData<%s, %s, true>' % (is_signed, is_normal) 281 282 if 'FIXED' in src_format: 283 assert 'FLOAT' in dst_format, ( 284 'get_vertex_copy_function: can only convert fixed to float,' + ' not to ' + dst_format) 285 return 'Copy32FixedTo32FVertexData<%d, %d>' % (src_num_channel, dst_num_channel) 286 287 src_gl_type = get_format_gl_type(src_format) 288 dst_gl_type = get_format_gl_type(dst_format) 289 290 if src_gl_type == None: 291 return "nullptr" 292 293 if src_gl_type == dst_gl_type: 294 default_alpha = '1' 295 296 if src_num_channel == dst_num_channel or dst_num_channel < 4: 297 default_alpha = '0' 298 elif 'A16_FLOAT' in dst_format: 299 default_alpha = 'gl::Float16One' 300 elif 'A32_FLOAT' in dst_format: 301 default_alpha = 'gl::Float32One' 302 elif 'NORM' in dst_format: 303 default_alpha = 'std::numeric_limits<%s>::max()' % (src_gl_type) 304 305 return 'CopyNativeVertexData<%s, %d, %d, %s>' % (src_gl_type, src_num_channel, 306 dst_num_channel, default_alpha) 307 308 assert 'FLOAT' in dst_format, ( 309 'get_vertex_copy_function: can only convert to float,' + ' not to ' + dst_format) 310 normalized = 'true' if 'NORM' in src_format else 'false' 311 312 dst_is_half = 'true' if dst_gl_type == 'GLhalf' else 'false' 313 return "CopyToFloatVertexData<%s, %d, %d, %s, %s>" % (src_gl_type, src_num_channel, 314 dst_num_channel, normalized, dst_is_half) 315