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