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