xref: /aosp_15_r20/external/mesa3d/src/vulkan/util/vk_physical_device_spirv_caps_gen.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1COPYRIGHT=u"""
2/* Copyright 2024 Valve Corporation
3 * Copyright 2021 Intel Corporation
4 * SPDX-License-Identifier: MIT
5 */
6"""
7
8import argparse
9from vk_physical_device_features_gen import get_renamed_feature, str_removeprefix
10import os
11import sys
12import xml.etree.ElementTree as et
13
14import mako
15from mako.template import Template
16
17TEMPLATE_C = Template(COPYRIGHT + """
18/* This file generated from ${filename}, don't edit directly. */
19
20#include "vk_physical_device.h"
21#include "vk_instance.h"
22#include "vk_shader.h"
23
24/* for spirv_supported_capabilities */
25#include "compiler/spirv/spirv_info.h"
26
27struct spirv_capabilities
28vk_physical_device_get_spirv_capabilities(const struct vk_physical_device *pdev)
29{
30   const struct vk_features *f = &pdev->supported_features;
31   const struct vk_device_extension_table *e = &pdev->supported_extensions;
32   const struct vk_properties *p = &pdev->properties;
33   uint32_t api_version = pdev->instance->app_info.api_version;
34
35   struct spirv_capabilities caps = { false, };
36
37   /* We |= for everything because some caps have multiple names but the
38    * same enum value and they sometimes have different enables in the
39    * Vulkan spec.  To handle this, we just | all the enables together.
40    */
41% for cap in caps:
42    caps.${cap} |= ${' | '.join(caps[cap])};
43% endfor
44
45   return caps;
46}
47""")
48
49# These don't exist in the SPIR-V headers for one reason or another.
50NON_EXISTANT_CAPS = [
51    # This isn't a cap, it's an execution mode.
52    #
53    # https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6618
54    'MaximallyReconvergesKHR',
55
56    # This extension got published but never got merged to SPIRV-Headers
57    #
58    # https://gitlab.khronos.org/spirv/spirv-extensions/-/merge_requests/238
59    'ClusterCullingShadingHUAWEI',
60
61    # Exclude the one beta cap.
62    'ShaderEnqueueAMDX',
63]
64
65def process_enable(enab):
66    attrib = enab.attrib
67
68    if 'property' in attrib:
69        if attrib['value'] == 'VK_TRUE':
70            return f"p->{attrib['member']}"
71        else:
72            return f"(p->{attrib['member']} & {attrib['value']})"
73    elif 'extension' in attrib:
74        return f"e->{str_removeprefix(attrib['extension'], 'VK_')}"
75    elif 'feature' in attrib:
76        feat = get_renamed_feature(attrib['struct'], attrib['feature'])
77        return f"f->{feat}"
78    else:
79        version = attrib['version']
80        return f"(api_version >= VK_API_{str_removeprefix(version, 'VK_')})"
81
82def get_capabilities(doc, beta):
83    caps = {}
84
85    for cap in doc.findall('./spirvcapabilities/spirvcapability'):
86        name = cap.attrib['name']
87        if name in NON_EXISTANT_CAPS:
88            continue
89
90        enables = cap.findall('enable')
91        lst = caps.setdefault(name, [])
92        lst += [process_enable(x) for x in enables]
93
94    # Remove duplicates
95    for cap in caps:
96        caps[cap] = list(dict.fromkeys(caps[cap]))
97
98    return caps
99
100
101def main():
102    parser = argparse.ArgumentParser()
103    parser.add_argument('--out-c', required=True, help='Output C file.')
104    parser.add_argument('--beta', required=True, help='Enable beta extensions.')
105    parser.add_argument('--xml', required=True, help='Vulkan API XML file.')
106    args = parser.parse_args()
107
108    environment = {
109        'filename': os.path.basename(__file__),
110        'caps': get_capabilities(et.parse(args.xml), args.beta),
111    }
112
113    try:
114        with open(args.out_c, 'w', encoding='utf-8') as f:
115            f.write(TEMPLATE_C.render(**environment))
116    except Exception:
117        # In the event there's an error, this uses some helpers from mako
118        # to print a useful stack trace and prints it, then exits with
119        # status 1, if python is run with debug; otherwise it just raises
120        # the exception
121        print(mako.exceptions.text_error_template().render(), file=sys.stderr)
122        sys.exit(1)
123
124if __name__ == '__main__':
125    main()
126