summaryrefslogtreecommitdiffstats
path: root/video/out/vulkan/utils.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2017-09-29 00:36:46 +0200
committerMartin Herkt <652892+lachs0r@users.noreply.github.com>2017-12-25 00:47:53 +0100
commitf2f91cf570ad6736a62192f2cb36b6c2887a0fda (patch)
treebd6237760eddc3c2642555d455d80230cd5a9257 /video/out/vulkan/utils.c
parent5feaaba0fd27af34ee1fef12545f1dd96ebefddd (diff)
downloadmpv-f2f91cf570ad6736a62192f2cb36b6c2887a0fda.tar.bz2
mpv-f2f91cf570ad6736a62192f2cb36b6c2887a0fda.tar.xz
vo_gpu: vulkan: add a vk_signal abstraction
This combines VkSemaphores and VkEvents into a common umbrella abstraction which can resolve to either. We aggressively try to prefer VkEvents over VkSemaphores whenever the conditions are met (1. we can unsignal the semaphore, i.e. it comes from the same frame; and 2. it comes from the same queue).
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,