• 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# 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