xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/gen_vk_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_vk_format_table.py:
7#  Code generation for vk format map. See vk_format_map.json for data source.
8#  NOTE: don't run this script directly. Run scripts/run_code_generation.py.
9
10import json
11import math
12import pprint
13import os
14import re
15import sys
16
17sys.path.append('..')
18import angle_format
19
20template_table_autogen_cpp = """// GENERATED FILE - DO NOT EDIT.
21// Generated by {script_name} using data from {input_file_name}
22//
23// Copyright 2020 The ANGLE Project Authors. All rights reserved.
24// Use of this source code is governed by a BSD-style license that can be
25// found in the LICENSE file.
26//
27// {out_file_name}:
28//   Queries for full Vulkan format information based on GL format.
29
30#include "libANGLE/renderer/vulkan/vk_format_utils.h"
31
32#include "image_util/loadimage.h"
33
34using namespace angle;
35
36namespace rx
37{{
38namespace vk
39{{
40
41void Format::initialize(Renderer *renderer,
42                        const angle::Format &angleFormat)
43{{
44    switch (angleFormat.id)
45    {{
46{format_case_data}
47        default:
48            UNREACHABLE();
49            break;
50    }}
51}}
52
53VkFormat GetVkFormatFromFormatID(const Renderer *renderer, angle::FormatID formatID)
54{{
55    static constexpr angle::FormatMap<VkFormat> kMap = {{
56{format_id_cases}
57    }};
58
59    return AdjustASTCFormatForHDR(renderer, kMap[formatID]);
60}}
61
62angle::FormatID GetFormatIDFromVkFormat(VkFormat vkFormat)
63{{
64    switch (vkFormat)
65    {{
66{vk_format_cases}
67        default:
68            UNREACHABLE();
69            return angle::FormatID::NONE;
70    }}
71}}
72}}  // namespace vk
73}}  // namespace rx
74"""
75
76empty_format_entry_template = """case angle::FormatID::{format_id}:
77// This format is not implemented in Vulkan.
78break;
79"""
80
81format_entry_template = """case angle::FormatID::{format_id}:
82mIntendedGLFormat = {internal_format};
83{image_template}
84{buffer_template}
85break;
86"""
87
88image_basic_template = """mActualSampleOnlyImageFormatID = {image};
89mImageInitializerFunction = {image_initializer};"""
90
91image_external_template = """mActualSampleOnlyImageFormatID = {image};
92mActualRenderableImageFormatID = {image};
93mImageInitializerFunction = {image_initializer};"""
94
95image_struct_template = "{{{image}, {image_initializer}}}"
96
97image_fallback_template = """{{
98static constexpr ImageFormatInitInfo kInfo[] = {{{image_list}}};
99initImageFallback(renderer, kInfo, ArraySize(kInfo));
100}}"""
101
102buffer_basic_template = """mActualBufferFormatID = {buffer};
103mVkBufferFormatIsPacked = {vk_buffer_format_is_packed};
104mVertexLoadFunction = {vertex_load_function};
105mVertexLoadRequiresConversion = {vertex_load_converts};"""
106
107buffer_struct_template = """{{{buffer}, {vk_buffer_format_is_packed},
108{vertex_load_function}, {vertex_load_converts}}}"""
109
110buffer_fallback_template = """{{
111static constexpr BufferFormatInitInfo kInfo[] = {{{buffer_list}}};
112initBufferFallback(renderer, kInfo, ArraySize(kInfo), {buffer_compressed_offset});
113}}"""
114
115
116def is_packed(format_id):
117    return "true" if "_PACK" in format_id else "false"
118
119
120def verify_vk_map_keys(angle_to_gl, vk_json_data):
121    """Verify that the keys in Vulkan format tables exist in the ANGLE table.  If they don't, the
122    entry in the Vulkan file is incorrect and needs to be fixed."""
123
124    no_error = True
125    for table in ["map", "fallbacks"]:
126        for angle_format in vk_json_data[table].keys():
127            if not angle_format in angle_to_gl.keys():
128                print("Invalid format " + angle_format + " in vk_format_map.json in " + table)
129                no_error = False
130
131    return no_error
132
133
134def get_vertex_copy_function(src_format, dst_format, vk_format):
135    if "_PACK" in vk_format:
136        pack_bits = int(re.search(r'_PACK(\d+)', vk_format).group(1))
137        base_type = None
138        if pack_bits == 8:
139            base_type = 'byte'
140        elif pack_bits == 16:
141            base_type = 'short'
142        elif pack_bits == 32:
143            base_type = 'int'
144        else:
145            return 'nullptr'
146        return 'CopyNativeVertexData<GLu%s, 1, 1, 0>' % base_type
147    if 'R10G10B10A2' in src_format:
148        # When the R10G10B10A2 type can't be used by the vertex buffer,
149        # it needs to be converted to the type which can be used by it.
150        is_signed = 'false' if 'UINT' in src_format or 'UNORM' in src_format or 'USCALED' in src_format else 'true'
151        normalized = 'true' if 'NORM' in src_format else 'false'
152        to_float = 'false' if 'INT' in src_format else 'true'
153        to_half = to_float
154        return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, %s, %s>' % (is_signed, normalized,
155                                                                     to_float, to_half)
156    return angle_format.get_vertex_copy_function(src_format, dst_format)
157
158
159def gen_format_case(angle, internal_format, vk_json_data):
160    vk_map = vk_json_data["map"]
161    vk_fallbacks = vk_json_data["fallbacks"]
162    args = dict(
163        format_id=angle, internal_format=internal_format, image_template="", buffer_template="")
164
165    if ((angle not in vk_map) and (angle not in vk_fallbacks)):
166        return empty_format_entry_template.format(**args)
167
168    # get_formats returns override format (if any) + fallbacks
169    # this was necessary to support D32_UNORM. There is no appropriate override that allows
170    # us to fallback to D32_FLOAT, so now we leave the image override empty and function will
171    # give us the fallbacks.
172    def get_formats(format, type):
173        fallbacks = vk_fallbacks.get(format, {}).get(type, [])
174        if not isinstance(fallbacks, list):
175            fallbacks = [fallbacks]
176
177        compressed = vk_fallbacks.get(format, {}).get(type + "_compressed", [])
178        if not isinstance(compressed, list):
179            compressed = [compressed]
180
181        fallbacks += compressed
182
183        if format in vk_map:
184            assert format not in fallbacks
185            fallbacks = [format] + fallbacks
186
187        return (fallbacks, len(fallbacks) - len(compressed))
188
189    def image_args(format):
190        return dict(
191            image="angle::FormatID::" + format,
192            image_initializer=angle_format.get_internal_format_initializer(
193                internal_format, format))
194
195    def buffer_args(format):
196        vk_buffer_format = vk_map[format]
197        return dict(
198            buffer="angle::FormatID::" + format,
199            vk_buffer_format_is_packed=is_packed(vk_buffer_format),
200            vertex_load_function=get_vertex_copy_function(angle, format, vk_buffer_format),
201            vertex_load_converts='false' if angle == format else 'true',
202        )
203
204    images, images_compressed_offset = get_formats(angle, "image")
205    if len(images) == 1:
206        if 'EXTERNAL' in angle:
207            args.update(image_template=image_external_template)
208        else:
209            args.update(image_template=image_basic_template)
210        args.update(image_args(images[0]))
211    elif len(images) > 1:
212        args.update(
213            image_template=image_fallback_template,
214            image_list=", ".join(image_struct_template.format(**image_args(i)) for i in images))
215
216    buffers, buffers_compressed_offset = get_formats(angle, "buffer")
217    if len(buffers) == 1:
218        args.update(buffer_template=buffer_basic_template)
219        args.update(buffer_args(buffers[0]))
220    elif len(buffers) > 1:
221        args.update(
222            buffer_template=buffer_fallback_template,
223            buffer_list=", ".join(
224                buffer_struct_template.format(**buffer_args(i)) for i in buffers),
225            buffer_compressed_offset=buffers_compressed_offset)
226
227    return format_entry_template.format(**args).format(**args)
228
229
230def get_format_id_case(format_id, vk_format):
231    return "{angle::FormatID::%s, %s}" % (format_id, vk_format)
232
233
234def get_vk_format_case(format_id, vk_format):
235    # don't generate the reverse mapping for the external format slots because they _all_ map
236    # to VK_FORMAT_UNDEFINED and so clash with NONE
237    if 'EXTERNAL' in format_id:
238        return ''
239    return """\
240        case %s:
241            return angle::FormatID::%s;
242""" % (vk_format, format_id)
243
244
245def main():
246
247    input_file_name = 'vk_format_map.json'
248    out_file_name = 'vk_format_table_autogen.cpp'
249
250    # auto_script parameters.
251    if len(sys.argv) > 1:
252        inputs = ['../angle_format.py', '../angle_format_map.json', input_file_name]
253        outputs = [out_file_name]
254
255        if sys.argv[1] == 'inputs':
256            print(','.join(inputs))
257        elif sys.argv[1] == 'outputs':
258            print(','.join(outputs))
259        else:
260            print('Invalid script parameters')
261            return 1
262        return 0
263
264    angle_to_gl = angle_format.load_inverse_table(os.path.join('..', 'angle_format_map.json'))
265    vk_json_data = angle_format.load_json(input_file_name)
266
267    if not verify_vk_map_keys(angle_to_gl, vk_json_data):
268        return 1
269
270    format_id_cases = [
271        get_format_id_case(format_id, vk_format)
272        for format_id, vk_format in sorted(vk_json_data["map"].items())
273    ]
274
275    vk_format_cases = [
276        get_vk_format_case(format_id, vk_format)
277        for format_id, vk_format in sorted(vk_json_data["map"].items())
278    ]
279
280    vk_cases = [
281        gen_format_case(angle, gl, vk_json_data) for angle, gl in sorted(angle_to_gl.items())
282    ]
283
284    output_cpp = template_table_autogen_cpp.format(
285        format_case_data="\n".join(vk_cases),
286        format_id_cases=",\n".join(format_id_cases),
287        vk_format_cases="".join(vk_format_cases),
288        script_name=os.path.basename(__file__),
289        out_file_name=out_file_name,
290        input_file_name=input_file_name)
291
292    with open(out_file_name, 'wt') as out_file:
293        out_file.write(output_cpp)
294        out_file.close()
295    return 0
296
297
298if __name__ == '__main__':
299    sys.exit(main())
300