vulkan: Add some auto-generated synchronization helpers

These are helpful for drivers to implement synchronization rules

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26407>
This commit is contained in:
Faith Ekstrand 2023-11-30 17:45:28 -06:00 committed by Marge Bot
parent 9ad51980de
commit fe12c1c29e
4 changed files with 299 additions and 1 deletions

View file

@ -109,6 +109,7 @@ vulkan_runtime_files = files(
'vk_sync_timeline.c', 'vk_sync_timeline.c',
'vk_sync_timeline.h', 'vk_sync_timeline.h',
'vk_synchronization.c', 'vk_synchronization.c',
'vk_synchronization.h',
'vk_texcompress_etc2.c', 'vk_texcompress_etc2.c',
'vk_texcompress_etc2.h', 'vk_texcompress_etc2.h',
'vk_video.c', 'vk_video.c',
@ -218,6 +219,18 @@ vk_physical_device_properties = custom_target(
depend_files : vk_physical_device_properties_gen_depend_files, depend_files : vk_physical_device_properties_gen_depend_files,
) )
vk_synchronization_helpers = custom_target(
'vk_synchronization_helpers',
input : [vk_synchronization_helpers_gen, vk_api_xml],
output : ['vk_synchronization_helpers.c', 'vk_synchronization_helpers.h'],
command : [
prog_python, '@INPUT0@', '--xml', '@INPUT1@',
'--out-c', '@OUTPUT0@',
'--beta', with_vulkan_beta.to_string()
],
depend_files : vk_synchronization_helpers_gen_depend_files,
)
vk_format_info = custom_target( vk_format_info = custom_target(
'vk_format_info', 'vk_format_info',
input : ['vk_format_info_gen.py', vk_api_xml], input : ['vk_format_info_gen.py', vk_api_xml],
@ -233,7 +246,8 @@ libvulkan_runtime = static_library(
[vulkan_runtime_files, vk_common_entrypoints, [vulkan_runtime_files, vk_common_entrypoints,
vk_cmd_queue, vk_cmd_enqueue_entrypoints, vk_cmd_queue, vk_cmd_enqueue_entrypoints,
vk_dispatch_trampolines, vk_physical_device_features, vk_dispatch_trampolines, vk_physical_device_features,
vk_physical_device_properties, vk_format_info], vk_physical_device_properties, vk_synchronization_helpers,
vk_format_info],
include_directories : [inc_include, inc_src], include_directories : [inc_include, inc_src],
dependencies : vulkan_runtime_deps, dependencies : vulkan_runtime_deps,
c_args : c_msvc_compat_args, c_args : c_msvc_compat_args,

View file

@ -0,0 +1,55 @@
/*
* Copyright © 2023 Collabora, Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef VK_SYNCHRONIZATION_H
#define VK_SYNCHRONIZATION_H
#include <vulkan/vulkan_core.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Expands pipeline stage group flags
*
* Some stages like VK_PIPELINE_SHADER_STAGE_2_ALL_GRAPHICS_BIT represent more
* than one stage. This helper expands any such bits out to the full set of
* individual stages bits they represent.
*/
VkPipelineStageFlags2
vk_expand_pipeline_stage_flags2(VkPipelineStageFlags2 stages);
/** Returns the set of read accesses allowed in the given stages */
VkAccessFlags2
vk_read_access2_for_pipeline_stage_flags2(VkPipelineStageFlags2 stages);
/** Returns the set of write accesses allowed in the given stages */
VkAccessFlags2
vk_write_access2_for_pipeline_stage_flags2(VkPipelineStageFlags2 stages);
#ifdef __cplusplus
}
#endif
#endif /* VK_SYNCHRONIZATION_H */

View file

@ -52,6 +52,9 @@ vk_physical_device_features_gen_depend_files = [
vk_physical_device_properties_gen_depend_files = [ vk_physical_device_properties_gen_depend_files = [
files('vk_extensions.py'), files('vk_extensions.py'),
] ]
vk_synchronization_helpers_gen_depend_files = [
files('vk_extensions.py'),
]
vk_entrypoints_gen = files('vk_entrypoints_gen.py') vk_entrypoints_gen = files('vk_entrypoints_gen.py')
vk_extensions_gen = files('vk_extensions_gen.py') vk_extensions_gen = files('vk_extensions_gen.py')
@ -60,6 +63,7 @@ vk_cmd_queue_gen = files('vk_cmd_queue_gen.py')
vk_dispatch_trampolines_gen = files('vk_dispatch_trampolines_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_features_gen = files('vk_physical_device_features_gen.py')
vk_physical_device_properties_gen = files('vk_physical_device_properties_gen.py') vk_physical_device_properties_gen = files('vk_physical_device_properties_gen.py')
vk_synchronization_helpers_gen = files('vk_synchronization_helpers_gen.py')
files_vulkan_util = files( files_vulkan_util = files(
'vk_alloc.c', 'vk_alloc.c',

View file

@ -0,0 +1,225 @@
COPYRIGHT=u"""
/* Copyright © 2023 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
"""
import argparse
import os
import textwrap
import xml.etree.ElementTree as et
from mako.template import Template
from vk_extensions import get_api_list
TEMPLATE_C = Template(COPYRIGHT + """\
#include "vk_synchronization.h"
VkPipelineStageFlags2
vk_expand_pipeline_stage_flags2(VkPipelineStageFlags2 stages)
{
% for (group_stage, stages) in group_stages.items():
if (stages & ${group_stage})
stages |= ${' |\\n '.join(stages)};
% endfor
if (stages & VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT) {
% for (guard, stage) in all_commands_stages:
% if guard is not None:
#ifdef ${guard}
% endif
stages |= ${stage};
% if guard is not None:
#endif
% endif
% endfor
}
return stages;
}
VkAccessFlags2
vk_read_access2_for_pipeline_stage_flags2(VkPipelineStageFlags2 stages)
{
VkAccessFlags2 access = 0;
% for ((guard, stages), access) in stages_read_access.items():
% if guard is not None:
#ifdef ${guard}
% endif
if (stages & (${' |\\n '.join(stages)}))
access |= ${' |\\n '.join(access)};
% if guard is not None:
#endif
% endif
% endfor
return access;
}
VkAccessFlags2
vk_write_access2_for_pipeline_stage_flags2(VkPipelineStageFlags2 stages)
{
VkAccessFlags2 access = 0;
% for ((guard, stages), access) in stages_write_access.items():
% if guard is not None:
#ifdef ${guard}
% endif
if (stages & (${' |\\n '.join(stages)}))
access |= ${' |\\n '.join(access)};
% if guard is not None:
#endif
% endif
% endfor
return access;
}
""")
def get_guards(xml, api):
guards = {}
for ext_elem in xml.findall('./extensions/extension'):
supported = get_api_list(ext_elem.attrib['supported'])
if api not in supported:
continue
for enum in ext_elem.findall('./require/enum[@extends]'):
if enum.attrib['extends'] not in ('VkPipelineStageFlagBits2',
'VkAccessFlagBits2'):
continue
if 'protect' not in enum.attrib:
continue
name = enum.attrib['name']
guard = enum.attrib['protect']
guards[name] = guard
return guards
def get_all_commands_stages(xml, guards):
stages = []
for stage in xml.findall('./sync/syncstage'):
stage_name = stage.attrib['name']
exclude = [
# This isn't a real stage
'VK_PIPELINE_STAGE_2_NONE',
# These are real stages but they're a bit weird to include in
# ALL_COMMANDS because they're context-dependent, depending on
# whether they're part of srcStagesMask or dstStagesMask.
#
# We could avoid all grouped stages but then if someone adds
# another group later, the behavior of this function may change in
# a backwards-compatible way. Also, the other ones aren't really
# hurting anything if we add them in.
'VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT',
'VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT',
# This is all COMMANDS, not host.
'VK_PIPELINE_STAGE_2_HOST_BIT',
]
if stage_name in exclude:
continue
guard = guards.get(stage_name, None)
stages.append((guard, stage_name))
return stages
def get_group_stages(xml):
group_stages = {}
for stage in xml.findall('./sync/syncstage'):
name = stage.attrib['name']
equiv = stage.find('./syncequivalent')
if equiv is not None:
stages = equiv.attrib['stage'].split(',')
group_stages[name] = stages
return group_stages
def access_is_read(name):
if 'READ' in name:
assert 'WRITE' not in name
return True
elif 'WRITE' in name:
return False
else:
print(name)
assert False, "Invalid access bit name"
def get_stages_access(xml, read, guards):
stages_access = {}
for access in xml.findall('./sync/syncaccess'):
access_name = access.attrib['name']
if access_name == 'VK_ACCESS_2_NONE':
continue
if access_is_read(access_name) != read:
continue
guard = guards.get(access_name, None)
support = access.find('./syncsupport')
if support is not None:
stages = support.attrib['stage'].split(',')
stages.sort()
key = (guard, tuple(stages))
if key in stages_access:
stages_access[key].append(access_name)
else:
stages_access[key] = [access_name]
return stages_access
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--beta', required=True, help='Enable beta extensions.')
parser.add_argument('--xml', required=True, help='Vulkan API XML file')
parser.add_argument('--out-c', required=True, help='Output C file.')
args = parser.parse_args()
xml = et.parse(args.xml);
guards = get_guards(xml, 'vulkan')
environment = {
'all_commands_stages': get_all_commands_stages(xml, guards),
'group_stages': get_group_stages(xml),
'stages_read_access': get_stages_access(xml, True, guards),
'stages_write_access': get_stages_access(xml, False, guards),
}
try:
with open(args.out_c, 'w') as f:
f.write(TEMPLATE_C.render(**environment))
except Exception:
# In the event there's an error, this imports 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
import sys
from mako import exceptions
print(exceptions.text_error_template().render(), file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()