blob: a50ad6050468aed752f502a189e7280043481531 [file] [log] [blame]
COPYRIGHT=u"""
/* Copyright 2024 Valve Corporation
* Copyright 2021 Intel Corporation
* SPDX-License-Identifier: MIT
*/
"""
import argparse
from vk_physical_device_features_gen import get_renamed_feature, str_removeprefix
import os
import sys
import xml.etree.ElementTree as et
import mako
from mako.template import Template
TEMPLATE_C = Template(COPYRIGHT + """
/* This file generated from ${filename}, don't edit directly. */
#include "vk_physical_device.h"
#include "vk_instance.h"
#include "vk_shader.h"
/* for spirv_supported_capabilities */
#include "compiler/spirv/spirv_info.h"
struct spirv_capabilities
vk_physical_device_get_spirv_capabilities(const struct vk_physical_device *pdev)
{
const struct vk_features *f = &pdev->supported_features;
const struct vk_device_extension_table *e = &pdev->supported_extensions;
const struct vk_properties *p = &pdev->properties;
uint32_t api_version = pdev->instance->app_info.api_version;
struct spirv_capabilities caps = { false, };
/* We |= for everything because some caps have multiple names but the
* same enum value and they sometimes have different enables in the
* Vulkan spec. To handle this, we just | all the enables together.
*/
% for cap in caps:
caps.${cap} |= ${' | '.join(caps[cap])};
% endfor
return caps;
}
""")
# These don't exist in the SPIR-V headers for one reason or another.
NON_EXISTANT_CAPS = [
# This isn't a cap, it's an execution mode.
#
# https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6618
'MaximallyReconvergesKHR',
# This extension got published but never got merged to SPIRV-Headers
#
# https://gitlab.khronos.org/spirv/spirv-extensions/-/merge_requests/238
'ClusterCullingShadingHUAWEI',
# Exclude the one beta cap.
'ShaderEnqueueAMDX',
]
def process_enable(enab):
attrib = enab.attrib
if 'property' in attrib:
if attrib['value'] == 'VK_TRUE':
return f"p->{attrib['member']}"
else:
return f"(p->{attrib['member']} & {attrib['value']})"
elif 'extension' in attrib:
return f"e->{str_removeprefix(attrib['extension'], 'VK_')}"
elif 'feature' in attrib:
feat = get_renamed_feature(attrib['struct'], attrib['feature'])
return f"f->{feat}"
else:
version = attrib['version']
return f"(api_version >= VK_API_{str_removeprefix(version, 'VK_')})"
def get_capabilities(doc, beta):
caps = {}
for cap in doc.findall('./spirvcapabilities/spirvcapability'):
name = cap.attrib['name']
if name in NON_EXISTANT_CAPS:
continue
enables = cap.findall('enable')
lst = caps.setdefault(name, [])
lst += [process_enable(x) for x in enables]
# Remove duplicates
for cap in caps:
caps[cap] = list(dict.fromkeys(caps[cap]))
return caps
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--out-c', required=True, help='Output C file.')
parser.add_argument('--beta', required=True, help='Enable beta extensions.')
parser.add_argument('--xml', required=True, help='Vulkan API XML file.')
args = parser.parse_args()
environment = {
'filename': os.path.basename(__file__),
'caps': get_capabilities(et.parse(args.xml), args.beta),
}
try:
with open(args.out_c, 'w', encoding='utf-8') as f:
f.write(TEMPLATE_C.render(**environment))
except Exception:
# In the event there's an error, this uses some helpers from mako
# to print a useful stack trace and prints it, then exits with
# status 1, if python is run with debug; otherwise it just raises
# the exception
print(mako.exceptions.text_error_template().render(), file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()