Module: Mesa
Branch: main
Commit: fe12c1c29e52e13c2dbda35d9621ce09ccf101c2
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=fe12c1c29e52e13c2dbda35d9621ce09ccf101c2

Author: Faith Ekstrand <faith.ekstr...@collabora.com>
Date:   Thu Nov 30 17:45:28 2023 -0600

vulkan: Add some auto-generated synchronization helpers

These are helpful for drivers to implement synchronization rules

Reviewed-by: Lionel Landwerlin <lionel.g.landwer...@intel.com>
Reviewed-by: Konstantin Seurer <konstantin.seu...@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26407>

---

 src/vulkan/runtime/meson.build                    |  16 +-
 src/vulkan/runtime/vk_synchronization.h           |  55 ++++++
 src/vulkan/util/meson.build                       |   4 +
 src/vulkan/util/vk_synchronization_helpers_gen.py | 225 ++++++++++++++++++++++
 4 files changed, 299 insertions(+), 1 deletion(-)

diff --git a/src/vulkan/runtime/meson.build b/src/vulkan/runtime/meson.build
index e4450f797f4..9f4e5730db5 100644
--- a/src/vulkan/runtime/meson.build
+++ b/src/vulkan/runtime/meson.build
@@ -109,6 +109,7 @@ vulkan_runtime_files = files(
   'vk_sync_timeline.c',
   'vk_sync_timeline.h',
   'vk_synchronization.c',
+  'vk_synchronization.h',
   'vk_texcompress_etc2.c',
   'vk_texcompress_etc2.h',
   'vk_video.c',
@@ -218,6 +219,18 @@ vk_physical_device_properties = custom_target(
   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',
   input : ['vk_format_info_gen.py', vk_api_xml],
@@ -233,7 +246,8 @@ libvulkan_runtime = static_library(
   [vulkan_runtime_files, vk_common_entrypoints,
    vk_cmd_queue, vk_cmd_enqueue_entrypoints,
    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],
   dependencies : vulkan_runtime_deps,
   c_args : c_msvc_compat_args,
diff --git a/src/vulkan/runtime/vk_synchronization.h 
b/src/vulkan/runtime/vk_synchronization.h
new file mode 100644
index 00000000000..da1565060e9
--- /dev/null
+++ b/src/vulkan/runtime/vk_synchronization.h
@@ -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 */
diff --git a/src/vulkan/util/meson.build b/src/vulkan/util/meson.build
index 451ca450720..90ebfd6fb71 100644
--- a/src/vulkan/util/meson.build
+++ b/src/vulkan/util/meson.build
@@ -52,6 +52,9 @@ vk_physical_device_features_gen_depend_files = [
 vk_physical_device_properties_gen_depend_files = [
   files('vk_extensions.py'),
 ]
+vk_synchronization_helpers_gen_depend_files = [
+  files('vk_extensions.py'),
+]
 
 vk_entrypoints_gen = files('vk_entrypoints_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_physical_device_features_gen = files('vk_physical_device_features_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(
   'vk_alloc.c',
diff --git a/src/vulkan/util/vk_synchronization_helpers_gen.py 
b/src/vulkan/util/vk_synchronization_helpers_gen.py
new file mode 100644
index 00000000000..46ed9ce1dd7
--- /dev/null
+++ b/src/vulkan/util/vk_synchronization_helpers_gen.py
@@ -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()

Reply via email to