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