mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2024-11-27 04:04:23 +08:00
vulkan: add helper to fill out spirv caps automatically
The Vulkan XML tells us exactly which caps are implied by which API versions, features, extensions, and properties. We just need to parse that and autogenerate some glue code, that way drivers don't need to track this manually. This reduces the boilerplate needed when bringing up new features. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Iván Briano <ivan.briano@intel.com> Acked-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28905>
This commit is contained in:
parent
ba11b12a82
commit
1759c0eba7
1
docs/header-stubs/compiler/spirv/spirv_info.h
Normal file
1
docs/header-stubs/compiler/spirv/spirv_info.h
Normal file
@ -0,0 +1 @@
|
||||
struct spirv_capabilities {};
|
@ -153,6 +153,17 @@ vk_physical_device_properties = custom_target(
|
||||
depend_files : vk_physical_device_properties_gen_depend_files,
|
||||
)
|
||||
|
||||
vk_physical_device_spirv_caps = custom_target(
|
||||
'vk_physical_device_spirv_caps',
|
||||
input : [vk_physical_device_spirv_caps_gen, vk_api_xml],
|
||||
output : 'vk_physical_device_spirv_caps.c',
|
||||
command : [
|
||||
prog_python, '@INPUT0@', '--xml', '@INPUT1@',
|
||||
'--out-c', '@OUTPUT0@', '--beta', with_vulkan_beta.to_string()
|
||||
],
|
||||
depend_files : vk_physical_device_spirv_caps_gen_depend_files,
|
||||
)
|
||||
|
||||
vk_synchronization_helpers = custom_target(
|
||||
'vk_synchronization_helpers',
|
||||
input : [vk_synchronization_helpers_gen, vk_api_xml],
|
||||
@ -183,6 +194,7 @@ vulkan_lite_runtime_files += [
|
||||
vk_format_info,
|
||||
vk_physical_device_features,
|
||||
vk_physical_device_properties,
|
||||
vk_physical_device_spirv_caps,
|
||||
vk_synchronization_helpers,
|
||||
]
|
||||
|
||||
@ -230,6 +242,7 @@ libvulkan_lite_instance = static_library(
|
||||
# - idep_vulkan_runtime
|
||||
idep_vulkan_lite_runtime_headers = declare_dependency(
|
||||
sources : [
|
||||
spirv_info_h,
|
||||
vk_cmd_enqueue_entrypoints[0],
|
||||
vk_cmd_queue[1],
|
||||
vk_common_entrypoints[0],
|
||||
|
@ -145,6 +145,9 @@ VkResult
|
||||
vk_physical_device_check_device_features(struct vk_physical_device *physical_device,
|
||||
const VkDeviceCreateInfo *pCreateInfo);
|
||||
|
||||
struct spirv_capabilities
|
||||
vk_physical_device_get_spirv_capabilities(const struct vk_physical_device *pdev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -52,6 +52,10 @@ vk_physical_device_features_gen_depend_files = [
|
||||
vk_physical_device_properties_gen_depend_files = [
|
||||
files('vk_extensions.py'),
|
||||
]
|
||||
vk_physical_device_spirv_caps_gen_depend_files = [
|
||||
files('vk_extensions.py'),
|
||||
files('vk_physical_device_features_gen.py'),
|
||||
]
|
||||
vk_synchronization_helpers_gen_depend_files = [
|
||||
files('vk_extensions.py'),
|
||||
]
|
||||
@ -63,6 +67,7 @@ vk_cmd_queue_gen = files('vk_cmd_queue_gen.py')
|
||||
vk_dispatch_trampolines_gen = files('vk_dispatch_trampolines_gen.py')
|
||||
vk_physical_device_features_gen = files('vk_physical_device_features_gen.py')
|
||||
vk_physical_device_properties_gen = files('vk_physical_device_properties_gen.py')
|
||||
vk_physical_device_spirv_caps_gen = files('vk_physical_device_spirv_caps_gen.py')
|
||||
vk_synchronization_helpers_gen = files('vk_synchronization_helpers_gen.py')
|
||||
|
||||
files_vulkan_util = files(
|
||||
|
125
src/vulkan/util/vk_physical_device_spirv_caps_gen.py
Normal file
125
src/vulkan/util/vk_physical_device_spirv_caps_gen.py
Normal file
@ -0,0 +1,125 @@
|
||||
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()
|
Loading…
Reference in New Issue
Block a user