summaryrefslogtreecommitdiffstats
path: root/video/out/vulkan/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/vulkan/utils.c')
-rw-r--r--video/out/vulkan/utils.c111
1 files changed, 111 insertions, 0 deletions
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,