• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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# 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 overrides.iteritems():
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 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
137    channels_pattern = re.compile('GL_(COMPRESSED_)?(SIGNED_)?(ETC\d_)?([A-Z]+)')
138    match = re.search(channels_pattern, internal_format)
139    channels_string = match.group(4)
140
141    if channels_string == 'ALPHA':
142        return 'a'
143    if channels_string == 'LUMINANCE':
144        if (internal_format.find('ALPHA') >= 0):
145            return 'la'
146        return 'l'
147    if channels_string == 'SRGB':
148        if (internal_format.find('ALPHA') >= 0):
149            return 'rgba'
150        return 'rgb'
151    if channels_string == 'DEPTH':
152        if (internal_format.find('STENCIL') >= 0):
153            return 'ds'
154        return 'd'
155    if channels_string == 'STENCIL':
156        return 's'
157    return channels_string.lower()
158
159
160def get_internal_format_initializer(internal_format, format_id):
161    gl_channels = gl_format_channels(internal_format)
162    gl_format_no_alpha = gl_channels == 'rgb' or gl_channels == 'l'
163    component_type, bits, channels = get_format_info(format_id)
164
165    if not gl_format_no_alpha or channels != 'rgba':
166        return 'nullptr'
167
168    elif 'BC1_' in format_id:
169        # BC1 is a special case since the texture data determines whether each block has an alpha channel or not.
170        # This if statement is hit by COMPRESSED_RGB_S3TC_DXT1, which is a bit of a mess.
171        # TODO(oetuaho): Look into whether COMPRESSED_RGB_S3TC_DXT1 works right in general.
172        # Reference: https://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt
173        return 'nullptr'
174
175    elif component_type == 'uint' and bits['R'] == 8:
176        return 'Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01>'
177    elif component_type == 'unorm' and bits['R'] == 8:
178        return 'Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>'
179    elif component_type == 'unorm' and bits['R'] == 16:
180        return 'Initialize4ComponentData<GLubyte, 0x0000, 0x0000, 0x0000, 0xFFFF>'
181    elif component_type == 'int' and bits['R'] == 8:
182        return 'Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01>'
183    elif component_type == 'snorm' and bits['R'] == 8:
184        return 'Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x7F>'
185    elif component_type == 'snorm' and bits['R'] == 16:
186        return 'Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x7FFF>'
187    elif component_type == 'float' and bits['R'] == 16:
188        return 'Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>'
189    elif component_type == 'uint' and bits['R'] == 16:
190        return 'Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001>'
191    elif component_type == 'int' and bits['R'] == 16:
192        return 'Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001>'
193    elif component_type == 'float' and bits['R'] == 32:
194        return 'Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>'
195    elif component_type == 'int' and bits['R'] == 32:
196        return 'Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000, 0x00000001>'
197    elif component_type == 'uint' and bits['R'] == 32:
198        return 'Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000, 0x00000001>'
199    else:
200        raise ValueError(
201            'warning: internal format initializer could not be generated and may be needed for ' +
202            internal_format)
203
204
205def get_format_gl_type(format):
206    sign = ''
207    base_type = None
208    if 'FLOAT' in format:
209        bits = get_bits(format)
210        redbits = bits and bits.get('R')
211        base_type = 'float'
212        if redbits == 16:
213            base_type = 'half'
214    else:
215        bits = get_bits(format)
216        redbits = bits and bits.get('R')
217        if redbits == 8:
218            base_type = 'byte'
219        elif redbits == 16:
220            base_type = 'short'
221        elif redbits == 32:
222            base_type = 'int'
223
224        if 'UINT' in format or 'UNORM' in format or 'USCALED' in format:
225            sign = 'u'
226
227    if base_type is None:
228        return None
229
230    return 'GL' + sign + base_type
231
232
233def get_vertex_copy_function(src_format, dst_format):
234    if dst_format == "NONE":
235        return "nullptr"
236
237    num_channel = len(get_channel_tokens(src_format))
238    if num_channel < 1 or num_channel > 4:
239        return "nullptr"
240
241    if 'FIXED' in src_format:
242        assert 'FLOAT' in dst_format, (
243            'get_vertex_copy_function: can only convert fixed to float,' + ' not to ' + dst_format)
244        return 'Copy32FixedTo32FVertexData<%d, %d>' % (num_channel, num_channel)
245
246    src_gl_type = get_format_gl_type(src_format)
247    dst_gl_type = get_format_gl_type(dst_format)
248
249    if src_gl_type == None:
250        return "nullptr"
251
252    if src_gl_type == dst_gl_type:
253        dst_num_channel = len(get_channel_tokens(dst_format))
254        return 'CopyNativeVertexData<%s, %d, %d, 0>' % (src_gl_type, num_channel, dst_num_channel)
255
256    assert 'FLOAT' in dst_format, (
257        'get_vertex_copy_function: can only convert to float,' + ' not to ' + dst_format)
258    normalized = 'true' if 'NORM' in src_format else 'false'
259
260    return "CopyTo32FVertexData<%s, %d, %d, %s>" % (src_gl_type, num_channel, num_channel,
261                                                    normalized)
262