summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/out/vulkan/common.h4
-rw-r--r--video/out/vulkan/utils.c111
-rw-r--r--video/out/vulkan/utils.h29
3 files changed, 144 insertions, 0 deletions
diff --git a/video/out/vulkan/common.h b/video/out/vulkan/common.h
index 35c5b3dbfb..de49c6f1af 100644
--- a/video/out/vulkan/common.h
+++ b/video/out/vulkan/common.h
@@ -53,6 +53,10 @@ struct mpvk_ctx {
struct vk_cmd *last_cmd; // most recently submitted (pending) command
struct spirv_compiler *spirv; // GLSL -> SPIR-V compiler
+ // Common pool of signals, to avoid having to re-create these objects often
+ struct vk_signal **signals;
+ int num_signals;
+
// Cached capabilities
VkPhysicalDeviceLimits limits;
};
diff --git a/video/out/vulkan/utils.c b/video/out/vulkan/utils.c
index ee5a524947..9d9d8d9820 100644
--- a/video/out/vulkan/utils.c
+++ b/video/out/vulkan/utils.c
@@ -140,6 +140,9 @@ void mpvk_uninit(struct mpvk_ctx *vk)
if (vk->dev) {
vk_cmdpool_destroy(vk, vk->pool);
+ for (int i = 0; i < vk->num_signals; i++)
+ vk_signal_destroy(vk, &vk->signals[i]);
+ talloc_free(vk->signals);
vk_malloc_uninit(vk);
vkDestroyDevice(vk->dev, MPVK_ALLOCATOR);
}
@@ -726,6 +729,114 @@ error:
return ret;
}
+void vk_signal_destroy(struct mpvk_ctx *vk, struct vk_signal **sig)
+{
+ if (!*sig)
+ return;
+
+ vkDestroySemaphore(vk->dev, (*sig)->semaphore, MPVK_ALLOCATOR);
+ vkDestroyEvent(vk->dev, (*sig)->event, MPVK_ALLOCATOR);
+ talloc_free(*sig);
+ *sig = NULL;
+}
+
+struct vk_signal *vk_cmd_signal(struct mpvk_ctx *vk, struct vk_cmd *cmd,
+ VkPipelineStageFlags stage)
+{
+ struct vk_signal *sig = NULL;
+ if (MP_TARRAY_POP(vk->signals, vk->num_signals, &sig))
+ goto done;
+
+ // no available signal => initialize a new one
+ sig = talloc_zero(NULL, struct vk_signal);
+ static const VkSemaphoreCreateInfo sinfo = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ };
+
+ VK(vkCreateSemaphore(vk->dev, &sinfo, MPVK_ALLOCATOR, &sig->semaphore));
+
+ static const VkEventCreateInfo einfo = {
+ .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
+ };
+
+ VK(vkCreateEvent(vk->dev, &einfo, MPVK_ALLOCATOR, &sig->event));
+
+done:
+ // Signal both the semaphore and the event. (We will only end up using one)
+ vk_cmd_sig(cmd, sig->semaphore);
+ vkCmdSetEvent(cmd->buf, sig->event, stage);
+ sig->event_source = cmd->queue;
+ return sig;
+
+error:
+ vk_signal_destroy(vk, &sig);
+ return NULL;
+}
+
+static bool unsignal_cmd(struct vk_cmd *cmd, VkSemaphore sem)
+{
+ for (int n = 0; n < cmd->num_sigs; n++) {
+ if (cmd->sigs[n] == sem) {
+ MP_TARRAY_REMOVE_AT(cmd->sigs, cmd->num_sigs, n);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Attempts to remove a queued signal operation. Returns true if sucessful,
+// i.e. the signal could be removed before it ever got fired.
+static bool unsignal(struct vk_cmd *cmd, VkSemaphore sem)
+{
+ if (unsignal_cmd(cmd, sem))
+ return true;
+
+ // Attempt to remove it from any queued commands
+ for (int i = 0; i < cmd->pool->num_cmds_queued; i++) {
+ if (unsignal_cmd(cmd->pool->cmds_queued[i], sem))
+ return true;
+ }
+
+ return false;
+}
+
+static void release_signal(struct mpvk_ctx *vk, struct vk_signal *sig)
+{
+ // The semaphore never needs to be recreated, because it's either
+ // unsignaled while still queued, or unsignaled as a result of a device
+ // wait. But the event *may* need to be reset, so just always reset it.
+ vkResetEvent(vk->dev, sig->event);
+ MP_TARRAY_APPEND(NULL, vk->signals, vk->num_signals, sig);
+}
+
+void vk_cmd_wait(struct mpvk_ctx *vk, struct vk_cmd *cmd,
+ struct vk_signal **sigptr, VkPipelineStageFlags stage,
+ VkEvent *out_event)
+{
+ struct vk_signal *sig = *sigptr;
+ if (!sig)
+ return;
+
+ if (out_event && sig->event && sig->event_source == cmd->queue &&
+ unsignal(cmd, sig->semaphore))
+ {
+ // If we can remove the semaphore signal operation from the history and
+ // pretend it never happened, then we get to use the VkEvent. This also
+ // requires that the VkEvent was signalled from the same VkQueue.
+ *out_event = sig->event;
+ } else if (sig->semaphore) {
+ // Otherwise, we use the semaphore. (This also unsignals it as a result
+ // of the command execution)
+ vk_cmd_dep(cmd, sig->semaphore, stage);
+ }
+
+ // In either case, once the command completes, we can release the signal
+ // resource back to the pool.
+ vk_cmd_callback(cmd, (vk_cb) release_signal, vk, sig);
+ *sigptr = NULL;
+}
+
const VkImageSubresourceRange vk_range = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
diff --git a/video/out/vulkan/utils.h b/video/out/vulkan/utils.h
index bdbbe0aa70..538897afae 100644
--- a/video/out/vulkan/utils.h
+++ b/video/out/vulkan/utils.h
@@ -121,6 +121,35 @@ void vk_cmd_dep(struct vk_cmd *cmd, VkSemaphore dep, VkPipelineStageFlags stage)
// after the command completes.
void vk_cmd_sig(struct vk_cmd *cmd, VkSemaphore sig);
+// Signal abstraction: represents an abstract synchronization mechanism.
+// Internally, this may either resolve as a semaphore or an event depending
+// on whether the appropriate conditions are met.
+struct vk_signal {
+ VkSemaphore semaphore;
+ VkEvent event;
+ VkQueue event_source;
+};
+
+// Generates a signal after the execution of all previous commands matching the
+// given the pipeline stage. The signal is owned by the caller, and must be
+// consumed eith vk_cmd_wait or released with vk_signal_cancel in order to
+// free the resources.
+struct vk_signal *vk_cmd_signal(struct mpvk_ctx *vk, struct vk_cmd *cmd,
+ VkPipelineStageFlags stage);
+
+// Consumes a previously generated signal. This signal must fire by the
+// indicated stage before the command can run. If *event is not NULL, then it
+// MAY be set to a VkEvent which the caller MUST manually wait on in the most
+// appropriate way. This function takes over ownership of the signal (and the
+// signal will be released/reused automatically)
+void vk_cmd_wait(struct mpvk_ctx *vk, struct vk_cmd *cmd,
+ struct vk_signal **sigptr, VkPipelineStageFlags stage,
+ VkEvent *out_event);
+
+// Destroys a currently pending signal, for example if the resource is no
+// longer relevant.
+void vk_signal_destroy(struct mpvk_ctx *vk, struct vk_signal **sig);
+
// Command pool / queue family hybrid abstraction
struct vk_cmdpool {
VkQueueFamilyProperties props;