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