vulkan: Add an emulated binary vk_sync type
authorJason Ekstrand <jason@jlekstrand.net>
Tue, 2 Nov 2021 15:20:00 +0000 (10:20 -0500)
committerJason Ekstrand <jason@jlekstrand.net>
Tue, 16 Nov 2021 16:54:27 +0000 (10:54 -0600)
This wraps a timeline vk_sync type and turns it into a binary one.  This
is useful for, for instance, driver layered on D3D12.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13427>

src/vulkan/runtime/meson.build
src/vulkan/runtime/vk_queue.c
src/vulkan/runtime/vk_sync_binary.c [new file with mode: 0644]
src/vulkan/runtime/vk_sync_binary.h [new file with mode: 0644]

index dfc3765..a49506c 100644 (file)
@@ -58,6 +58,8 @@ vulkan_runtime_files = files(
   'vk_shader_module.h',
   'vk_sync.c',
   'vk_sync.h',
+  'vk_sync_binary.c',
+  'vk_sync_binary.h',
   'vk_sync_timeline.c',
   'vk_sync_timeline.h',
   'vk_synchronization2.c',
index 6a2e44c..6227383 100644 (file)
@@ -35,6 +35,7 @@
 #include "vk_physical_device.h"
 #include "vk_semaphore.h"
 #include "vk_sync.h"
+#include "vk_sync_binary.h"
 #include "vk_sync_timeline.h"
 #include "vk_util.h"
 
@@ -281,6 +282,13 @@ vk_queue_submit_final(struct vk_queue *queue,
          submit->waits[i].wait_value = 0;
       }
 
+      struct vk_sync_binary *binary =
+         vk_sync_as_binary(submit->waits[i].sync);
+      if (binary) {
+         submit->waits[i].sync = &binary->timeline;
+         submit->waits[i].wait_value = binary->next_point;
+      }
+
       assert((submit->waits[i].sync->flags & VK_SYNC_IS_TIMELINE) ||
              submit->waits[i].wait_value == 0);
 
@@ -300,6 +308,13 @@ vk_queue_submit_final(struct vk_queue *queue,
    for (uint32_t i = 0; i < submit->signal_count; i++) {
       assert((submit->signals[i].sync->flags & VK_SYNC_IS_TIMELINE) ||
              submit->signals[i].signal_value == 0);
+
+      struct vk_sync_binary *binary =
+         vk_sync_as_binary(submit->signals[i].sync);
+      if (binary) {
+         submit->signals[i].sync = &binary->timeline;
+         submit->signals[i].signal_value = ++binary->next_point;
+      }
    }
 
    result = queue->driver_submit(queue, submit);
diff --git a/src/vulkan/runtime/vk_sync_binary.c b/src/vulkan/runtime/vk_sync_binary.c
new file mode 100644 (file)
index 0000000..3d2720f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2021 Intel Corporation
+ *
+ * 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.
+ */
+
+#include "vk_sync_binary.h"
+
+#include "vk_util.h"
+
+static struct vk_sync_binary *
+to_vk_sync_binary(struct vk_sync *sync)
+{
+   assert(sync->type->init == vk_sync_binary_init);
+
+   return container_of(sync, struct vk_sync_binary, sync);
+}
+
+VkResult
+vk_sync_binary_init(struct vk_device *device,
+                    struct vk_sync *sync,
+                    uint64_t initial_value)
+{
+   struct vk_sync_binary *binary = to_vk_sync_binary(sync);
+
+   const struct vk_sync_binary_type *btype =
+      container_of(binary->sync.type, struct vk_sync_binary_type, sync);
+
+   assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
+   assert(!(sync->flags & VK_SYNC_IS_SHAREABLE));
+
+   binary->next_point = (initial_value == 0);
+
+   return vk_sync_init(device, &binary->timeline, btype->timeline_type,
+                       VK_SYNC_IS_TIMELINE, 0 /* initial_value */);
+}
+
+static void
+vk_sync_binary_finish(struct vk_device *device,
+                      struct vk_sync *sync)
+{
+   struct vk_sync_binary *binary = to_vk_sync_binary(sync);
+
+   vk_sync_finish(device, &binary->timeline);
+}
+
+static VkResult
+vk_sync_binary_reset(struct vk_device *device,
+                     struct vk_sync *sync)
+{
+   struct vk_sync_binary *binary = to_vk_sync_binary(sync);
+
+   binary->next_point++;
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+vk_sync_binary_signal(struct vk_device *device,
+                      struct vk_sync *sync,
+                      uint64_t value)
+{
+   struct vk_sync_binary *binary = to_vk_sync_binary(sync);
+
+   assert(value == 0);
+
+   return vk_sync_signal(device, &binary->timeline, binary->next_point);
+}
+
+static VkResult
+vk_sync_binary_wait_many(struct vk_device *device,
+                         uint32_t wait_count,
+                         const struct vk_sync_wait *waits,
+                         enum vk_sync_wait_flags wait_flags,
+                         uint64_t abs_timeout_ns)
+{
+   STACK_ARRAY(struct vk_sync_wait, timeline_waits, wait_count);
+
+   for (uint32_t i = 0; i < wait_count; i++) {
+      struct vk_sync_binary *binary = to_vk_sync_binary(waits[i].sync);
+
+      timeline_waits[i] = (struct vk_sync_wait) {
+         .sync = &binary->timeline,
+         .stage_mask = waits[i].stage_mask,
+         .wait_value = binary->next_point,
+      };
+   }
+
+   VkResult result = vk_sync_wait_many(device, wait_count, timeline_waits, 
+                                       wait_flags, abs_timeout_ns);
+
+   STACK_ARRAY_FINISH(timeline_waits);
+
+   return result;
+}
+
+struct vk_sync_binary_type
+vk_sync_binary_get_type(const struct vk_sync_type *timeline_type)
+{
+   assert(timeline_type->features & VK_SYNC_FEATURE_TIMELINE);
+
+   return (struct vk_sync_binary_type) {
+      .sync = {
+         .size = offsetof(struct vk_sync_binary, timeline) +
+                 timeline_type->size,
+         .features = VK_SYNC_FEATURE_BINARY |
+                     VK_SYNC_FEATURE_GPU_WAIT |
+                     VK_SYNC_FEATURE_CPU_WAIT |
+                     VK_SYNC_FEATURE_CPU_RESET |
+                     VK_SYNC_FEATURE_CPU_SIGNAL |
+                     VK_SYNC_FEATURE_WAIT_ANY |
+                     VK_SYNC_FEATURE_WAIT_PENDING,
+         .init = vk_sync_binary_init,
+         .finish = vk_sync_binary_finish,
+         .reset = vk_sync_binary_reset,
+         .signal = vk_sync_binary_signal,
+         .wait_many = vk_sync_binary_wait_many,
+      },
+      .timeline_type = timeline_type,
+   };
+}
diff --git a/src/vulkan/runtime/vk_sync_binary.h b/src/vulkan/runtime/vk_sync_binary.h
new file mode 100644 (file)
index 0000000..8a4ceeb
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2021 Intel Corporation
+ *
+ * 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_SYNC_BINARY_H
+#define VK_SYNC_BINARY_H
+
+#include "vk_sync.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct vk_sync_binary_type {
+   struct vk_sync_type sync;
+   const struct vk_sync_type *timeline_type;
+};
+
+struct vk_sync_binary_type
+vk_sync_binary_get_type(const struct vk_sync_type *timeline_type);
+
+/** Implements a binary vk_sync type on top of a timeline vk_sync
+ *
+ * This is useful when targeting Windows APIs such as D3D12 which only have
+ * timelines and have no concept of a binary synchronization object.  Because
+ * binary vk_sync emulation requires tracking additional state (the next time
+ * point), fences and semaphores created from this type cannot support any of
+ * the sharing APIs.
+ */
+struct vk_sync_binary {
+   struct vk_sync sync;
+
+   uint64_t next_point;
+
+   struct vk_sync timeline;
+};
+
+VkResult vk_sync_binary_init(struct vk_device *device,
+                             struct vk_sync *sync,
+                             uint64_t initial_value);
+
+static inline bool
+vk_sync_type_is_vk_sync_binary(const struct vk_sync_type *type)
+{
+   return type->init == vk_sync_binary_init;
+}
+
+static inline struct vk_sync_binary *
+vk_sync_as_binary(struct vk_sync *sync)
+{
+   if (!vk_sync_type_is_vk_sync_binary(sync->type))
+      return NULL;
+
+   return container_of(sync, struct vk_sync_binary, sync);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VK_TIMELINE_H */