xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gen_angle_format_table.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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# 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
12import json
13import math
14import os
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 2020 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 2020 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#include "libANGLE/cl_types.h"
60
61#include "image_util/copyimage.h"
62#include "image_util/generatemip.h"
63#include "image_util/loadimage.h"
64
65namespace angle
66{{
67
68static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {{angle::FormatID::R8G8B8A8_UNORM,
69                                                             CopyBGRA8ToRGBA8}};
70static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {{&BGRAEntry, 1}};
71static constexpr rx::FastCopyFunctionMap NoCopyFunctions;
72
73const Format gFormatInfoTable[] = {{
74    // clang-format off
75    {{ FormatID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, false, false, false, gl::VertexAttribType::InvalidEnum }},
76{angle_format_info_cases}    // clang-format on
77}};
78
79// static
80FormatID Format::InternalFormatToID(GLenum internalFormat)
81{{
82    switch (internalFormat)
83    {{
84{angle_format_switch}
85    }}
86}}
87
88#if defined(ANGLE_ENABLE_CL)
89// static
90FormatID Format::CLRFormatToID(cl_channel_type internalChannelType)
91{{
92    switch (internalChannelType)
93    {{
94{angle_r_format_switch}
95    }}
96}}
97
98// static
99FormatID Format::CLRGFormatToID(cl_channel_type internalChannelType)
100{{
101    switch (internalChannelType)
102    {{
103{angle_rg_format_switch}
104    }}
105}}
106
107// static
108FormatID Format::CLRGBFormatToID(cl_channel_type internalChannelType)
109{{
110    switch (internalChannelType)
111    {{
112{angle_rgb_format_switch}
113    }}
114}}
115
116// static
117FormatID Format::CLRGBAFormatToID(cl_channel_type internalChannelType)
118{{
119    switch (internalChannelType)
120    {{
121{angle_rgba_format_switch}
122    }}
123}}
124
125// static
126FormatID Format::CLBGRAFormatToID(cl_channel_type internalChannelType)
127{{
128    switch (internalChannelType)
129    {{
130{angle_bgra_format_switch}
131    }}
132}}
133
134// static
135FormatID Format::CLsRGBAFormatToID(cl_channel_type internalChannelType)
136{{
137    switch (internalChannelType)
138    {{
139{angle_srgba_format_switch}
140    }}
141}}
142
143// static
144FormatID Format::CLDEPTHFormatToID(cl_channel_type internalChannelType)
145{{
146    switch (internalChannelType)
147    {{
148{angle_depth_format_switch}
149    }}
150}}
151
152// static
153FormatID Format::CLDEPTHSTENCILFormatToID(cl_channel_type internalChannelType)
154{{
155    switch (internalChannelType)
156    {{
157{angle_depth_stencil_format_switch}
158    }}
159}}
160#endif  // ANGLE_ENABLE_CL
161
162const Format *GetFormatInfoTable()
163{{
164    return gFormatInfoTable;
165}}
166}}  // namespace angle
167"""
168
169
170def ceil_int(value, mod):
171    assert mod > 0 and value > 0, 'integer modulation should be larger than 0'
172    return (value + mod - 1) // mod
173
174
175def is_depth_stencil(angle_format):
176    if not 'channels' in angle_format or not angle_format['channels']:
177        return False
178    return 'd' in angle_format['channels'] or 's' in angle_format['channels']
179
180
181def get_component_suffix(angle_format):
182    if angle_format['componentType'] == 'float':
183        return 'F'
184    if angle_format['componentType'] == 'int' or angle_format['componentType'] == 'snorm':
185        return 'S'
186    return ""
187
188
189def get_channel_struct(angle_format):
190    if 'bits' not in angle_format or angle_format['bits'] is None:
191        return None
192    if 'BLOCK' in angle_format['id']:
193        return None
194    if 'VERTEX' in angle_format['id']:
195        return None
196    if 'EXTERNAL' in angle_format['id']:
197        return None
198
199    bits = angle_format['bits']
200
201    if 'channelStruct' in angle_format:
202        return angle_format['channelStruct']
203
204    struct_name = ''
205    component_suffix = get_component_suffix(angle_format)
206
207    for channel in angle_format['channels']:
208        if channel == 'r':
209            struct_name += 'R{}'.format(bits['R'])
210        if channel == 'g':
211            struct_name += 'G{}'.format(bits['G'])
212        if channel == 'b':
213            struct_name += 'B{}'.format(bits['B'])
214        if channel == 'a':
215            struct_name += 'A{}'.format(bits['A'])
216        if channel == 'l':
217            struct_name += 'L{}'.format(bits['L'])
218        if channel == 'd':
219            struct_name += 'D{}'.format(bits['D']) + component_suffix
220        if channel == 's':
221            struct_name += 'S{}'.format(bits['S'])
222        if channel == 'x':
223            struct_name += 'X{}'.format(bits['X'])
224
225    if not is_depth_stencil(angle_format):
226        struct_name += component_suffix
227
228    return struct_name
229
230
231def get_mip_generation_function(angle_format):
232    channel_struct = get_channel_struct(angle_format)
233    if is_depth_stencil(angle_format) or channel_struct == None \
234            or "BLOCK" in angle_format["id"] or "VERTEX" in angle_format["id"]:
235        return 'nullptr'
236    return 'GenerateMip<' + channel_struct + '>'
237
238
239def get_color_read_write_component_type(angle_format):
240    component_type_map = {
241        'uint': 'GLuint',
242        'int': 'GLint',
243        'unorm': 'GLfloat',
244        'snorm': 'GLfloat',
245        'float': 'GLfloat'
246    }
247    return component_type_map[angle_format['componentType']]
248
249
250def get_color_read_function(angle_format):
251    channel_struct = get_channel_struct(angle_format)
252    if channel_struct == None:
253        return 'nullptr'
254
255    if is_depth_stencil(angle_format):
256        return 'ReadDepthStencil<' + channel_struct + '>'
257
258    read_component_type = get_color_read_write_component_type(angle_format)
259    return 'ReadColor<' + channel_struct + ', ' + read_component_type + '>'
260
261
262def get_color_write_function(angle_format):
263    channel_struct = get_channel_struct(angle_format)
264    if channel_struct == None:
265        return 'nullptr'
266
267    if is_depth_stencil(angle_format):
268        return 'WriteDepthStencil<' + channel_struct + '>'
269
270    write_component_type = get_color_read_write_component_type(angle_format)
271    return 'WriteColor<' + channel_struct + ', ' + write_component_type + '>'
272
273
274format_entry_template = """    {{ FormatID::{id}, {glInternalFormat}, {fboImplementationInternalFormat}, {mipGenerationFunction}, {fastCopyFunctions}, {colorReadFunction}, {colorWriteFunction}, {namedComponentType}, {R}, {G}, {B}, {A}, {L}, {D}, {S}, {pixelBytes}, {componentAlignmentMask}, {isBlock}, {isFixed}, {isScaled}, {isSRGB}, {isYUV}, {vertexAttribType} }},
275"""
276
277
278def get_named_component_type(component_type):
279    if component_type == "snorm":
280        return "GL_SIGNED_NORMALIZED"
281    elif component_type == "unorm":
282        return "GL_UNSIGNED_NORMALIZED"
283    elif component_type == "float":
284        return "GL_FLOAT"
285    elif component_type == "uint":
286        return "GL_UNSIGNED_INT"
287    elif component_type == "int":
288        return "GL_INT"
289    elif component_type == "none":
290        return "GL_NONE"
291    else:
292        raise ValueError("Unknown component type for " + component_type)
293
294
295def get_component_alignment_mask(channels, bits):
296    if channels == None or bits == None:
297        return "std::numeric_limits<GLuint>::max()"
298    bitness = bits[channels[0].upper()]
299    for channel in channels:
300        if channel not in "rgba":
301            return "std::numeric_limits<GLuint>::max()"
302        # Can happen for RGB10A2 formats.
303        if bits[channel.upper()] != bitness:
304            return "std::numeric_limits<GLuint>::max()"
305    component_bytes = (int(bitness) >> 3)
306
307    if component_bytes == 1:
308        return "0"
309    elif component_bytes == 2:
310        return "1"
311    elif component_bytes == 4:
312        return "3"
313    else:
314        # Can happen for 4-bit RGBA.
315        return "std::numeric_limits<GLuint>::max()"
316
317
318def get_vertex_attrib_type(format_id):
319
320    has_u = "_U" in format_id
321    has_s = "_S" in format_id
322    has_float = "_FLOAT" in format_id
323    has_fixed = "_FIXED" in format_id
324    has_r8 = "R8" in format_id
325    has_r16 = "R16" in format_id
326    has_r32 = "R32" in format_id
327    has_r10 = "R10" in format_id
328    has_vertex = "VERTEX" in format_id
329
330    if has_fixed:
331        return "Fixed"
332
333    if has_float:
334        return "HalfFloat" if has_r16 else "Float"
335
336    if has_r8:
337        return "Byte" if has_s else "UnsignedByte"
338
339    if has_r10:
340        if has_vertex:
341            return "Int1010102" if has_s else "UnsignedInt1010102"
342        else:
343            return "Int2101010" if has_s else "UnsignedInt2101010"
344
345    if has_r16:
346        return "Short" if has_s else "UnsignedShort"
347
348    if has_r32:
349        return "Int" if has_s else "UnsignedInt"
350
351    # Many ANGLE formats don't correspond with vertex formats.
352    return "InvalidEnum"
353
354
355def bool_str(cond):
356    return "true" if cond else "false"
357
358
359def json_to_table_data(format_id, json, angle_to_gl):
360
361    table_data = ""
362
363    parsed = {
364        "id": format_id,
365        "fastCopyFunctions": "NoCopyFunctions",
366    }
367
368    for k, v in sorted(json.items()):
369        parsed[k] = v
370
371    if "glInternalFormat" not in parsed:
372        parsed["glInternalFormat"] = angle_to_gl[format_id]
373
374    if "fboImplementationInternalFormat" not in parsed:
375        parsed["fboImplementationInternalFormat"] = parsed["glInternalFormat"]
376
377    if "componentType" not in parsed:
378        parsed["componentType"] = angle_format.get_component_type(format_id)
379
380    if "channels" not in parsed:
381        parsed["channels"] = angle_format.get_channels(format_id)
382
383    if "bits" not in parsed:
384        parsed["bits"] = angle_format.get_bits(format_id)
385
386    # Derived values.
387    parsed["mipGenerationFunction"] = get_mip_generation_function(parsed)
388    parsed["colorReadFunction"] = get_color_read_function(parsed)
389    parsed["colorWriteFunction"] = get_color_write_function(parsed)
390
391    for channel in angle_format.kChannels:
392        if parsed["bits"] != None and channel in parsed["bits"]:
393            parsed[channel] = parsed["bits"][channel]
394        else:
395            parsed[channel] = "0"
396
397    parsed["namedComponentType"] = get_named_component_type(parsed["componentType"])
398
399    if format_id == "B8G8R8A8_UNORM":
400        parsed["fastCopyFunctions"] = "BGRACopyFunctions"
401
402    is_block = format_id.endswith("_BLOCK")
403
404    pixel_bytes = 0
405    if is_block:
406        assert 'blockPixelBytes' in parsed, \
407            'Compressed format %s requires its block size to be specified in angle_format_data.json' % \
408                format_id
409        pixel_bytes = parsed['blockPixelBytes']
410    else:
411        sum_of_bits = 0
412        for channel in angle_format.kChannels:
413            sum_of_bits += int(parsed[channel])
414        pixel_bytes = ceil_int(sum_of_bits, 8)
415    parsed["pixelBytes"] = pixel_bytes
416    parsed["componentAlignmentMask"] = get_component_alignment_mask(parsed["channels"],
417                                                                    parsed["bits"])
418    parsed["isBlock"] = bool_str(is_block)
419    parsed["isFixed"] = bool_str("FIXED" in format_id)
420    parsed["isScaled"] = bool_str("SCALED" in format_id)
421    parsed["isSRGB"] = bool_str("SRGB" in format_id)
422    # For now we only look for the 'PLANE' or 'EXTERNAL' substring in format string. Expand this condition
423    # when adding support for YUV formats that have different identifying markers.
424    parsed["isYUV"] = bool_str("PLANE" in format_id or "EXTERNAL" in format_id)
425
426    parsed["vertexAttribType"] = "gl::VertexAttribType::" + get_vertex_attrib_type(format_id)
427
428    return format_entry_template.format(**parsed)
429
430
431# For convenience of the Vulkan backend, place depth/stencil formats first.  This allows
432# depth/stencil format IDs to be placed in only a few bits.
433def sorted_ds_first(all_angle):
434    ds_sorted = []
435    color_sorted = []
436    external_sorted = []
437    for format_id in sorted(all_angle):
438        if format_id == 'NONE':
439            continue
440        if 'EXTERNAL' in format_id:
441            external_sorted.append(format_id)
442        elif format_id[0] == 'D' or format_id[0] == 'S':
443            ds_sorted.append(format_id)
444        else:
445            color_sorted.append(format_id)
446
447    return ds_sorted + color_sorted + external_sorted
448
449
450def parse_angle_format_table(all_angle, json_data, angle_to_gl):
451    table_data = ''
452    for format_id in sorted_ds_first(all_angle):
453        assert (format_id != 'NONE')
454        format_info = json_data[format_id] if format_id in json_data else {}
455        table_data += json_to_table_data(format_id, format_info, angle_to_gl)
456
457    return table_data
458
459
460def gen_enum_string(all_angle):
461    enum_data = '    NONE'
462    for format_id in sorted_ds_first(all_angle):
463        assert (format_id != 'NONE')
464        enum_data += ',\n    ' + format_id
465    return enum_data
466
467
468case_template = """        case {gl_format}:
469            return FormatID::{angle_format};
470"""
471
472
473def gen_map_switch_string(gl_to_angle):
474    switch_data = ''
475    for gl_format in sorted(gl_to_angle.keys()):
476        angle_format = gl_to_angle[gl_format]
477        switch_data += case_template.format(gl_format=gl_format, angle_format=angle_format)
478    switch_data += "        default:\n"
479    switch_data += "            return FormatID::NONE;"
480    return switch_data
481
482
483def main():
484
485    # auto_script parameters.
486    if len(sys.argv) > 1:
487        inputs = ['angle_format.py', 'angle_format_data.json', 'angle_format_map.json']
488        outputs = ['Format_table_autogen.cpp', 'FormatID_autogen.h']
489
490        if sys.argv[1] == 'inputs':
491            print(','.join(inputs))
492        elif sys.argv[1] == 'outputs':
493            print(','.join(outputs))
494        else:
495            print('Invalid script parameters')
496            return 1
497        return 0
498
499    gl_to_angle = angle_format.load_forward_table('angle_format_map.json')
500
501    cl_r_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "r")
502    cl_rg_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rg")
503    cl_rgb_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rgb")
504    cl_rgba_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "rgba")
505    cl_bgra_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "bgra")
506    cl_srgba_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "srgba")
507    cl_depth_to_angle = angle_format.load_forward_table('angle_cl_format_map.json', "depth")
508    cl_depth_stencil_to_angle = angle_format.load_forward_table('angle_cl_format_map.json',
509                                                                "depth_stencil")
510
511    angle_to_gl = angle_format.load_inverse_table('angle_format_map.json')
512    data_source_name = 'angle_format_data.json'
513    json_data = angle_format.load_json(data_source_name)
514    all_angle = angle_to_gl.keys()
515
516    angle_format_cases = parse_angle_format_table(all_angle, json_data, angle_to_gl)
517    switch_data = gen_map_switch_string(gl_to_angle)
518
519    cl_r_switch_data = gen_map_switch_string(cl_r_to_angle)
520    cl_rg_switch_data = gen_map_switch_string(cl_rg_to_angle)
521    cl_rgb_switch_data = gen_map_switch_string(cl_rgb_to_angle)
522    cl_rgba_switch_data = gen_map_switch_string(cl_rgba_to_angle)
523    cl_bgra_switch_data = gen_map_switch_string(cl_bgra_to_angle)
524    cl_srgba_switch_data = gen_map_switch_string(cl_srgba_to_angle)
525    cl_depth_switch_data = gen_map_switch_string(cl_depth_to_angle)
526    cl_depth_stencil_switch_data = gen_map_switch_string(cl_depth_stencil_to_angle)
527
528    output_cpp = template_autogen_inl.format(
529        script_name=os.path.basename(sys.argv[0]),
530        angle_format_info_cases=angle_format_cases,
531        angle_format_switch=switch_data,
532        data_source_name=data_source_name,
533        angle_r_format_switch=cl_r_switch_data,
534        angle_rg_format_switch=cl_rg_switch_data,
535        angle_rgb_format_switch=cl_rgb_switch_data,
536        angle_rgba_format_switch=cl_rgba_switch_data,
537        angle_bgra_format_switch=cl_bgra_switch_data,
538        angle_srgba_format_switch=cl_srgba_switch_data,
539        angle_depth_format_switch=cl_depth_switch_data,
540        angle_depth_stencil_format_switch=cl_depth_stencil_switch_data)
541
542    with open('Format_table_autogen.cpp', 'wt') as out_file:
543        out_file.write(output_cpp)
544        out_file.close()
545
546    enum_data = gen_enum_string(all_angle)
547    num_angle_formats = len(all_angle)
548    output_h = template_autogen_h.format(
549        script_name=os.path.basename(sys.argv[0]),
550        angle_format_enum=enum_data,
551        data_source_name=data_source_name,
552        num_angle_formats=num_angle_formats)
553    with open('FormatID_autogen.h', 'wt') as out_file:
554        out_file.write(output_h)
555        out_file.close()
556
557    return 0
558
559
560if __name__ == '__main__':
561    sys.exit(main())
562