vkswapper: Use the trash list to free resources after they've been used
authorMatthew Waters <matthew@centricular.com>
Thu, 1 Sep 2016 10:04:08 +0000 (20:04 +1000)
committerMatthew Waters <matthew@centricular.com>
Thu, 3 Nov 2016 05:58:35 +0000 (16:58 +1100)
This allows further parallelism and removes a device wait from the end of
the render code.

ext/vulkan/vkswapper.c

index d528f0b..75f86ab 100644 (file)
@@ -41,6 +41,8 @@ G_DEFINE_TYPE_WITH_CODE (GstVulkanSwapper, gst_vulkan_swapper,
 struct _GstVulkanSwapperPrivate
 {
   GMutex render_lock;
+
+  GList *trash_list;
 };
 
 static void _on_window_draw (GstVulkanWindow * window,
@@ -333,6 +335,11 @@ gst_vulkan_swapper_finalize (GObject * object)
   GstVulkanSwapper *swapper = GST_VULKAN_SWAPPER (object);
   int i;
 
+  if (!gst_vulkan_trash_list_wait (swapper->priv->trash_list, -1))
+    GST_WARNING_OBJECT (swapper, "Failed to wait for all fences to complete "
+        "before shutting down");
+  swapper->priv->trash_list = NULL;
+
   if (swapper->swap_chain_images) {
     for (i = 0; i < swapper->n_swap_chain_images; i++) {
       gst_memory_unref ((GstMemory *) swapper->swap_chain_images[i]);
@@ -488,36 +495,20 @@ _swapper_set_image_layout_with_cmd (GstVulkanSwapper * swapper,
 }
 
 static gboolean
-_new_fence (GstVulkanDevice * device, VkFence * fence, GError ** error)
-{
-  VkFenceCreateInfo fence_info;
-  VkResult err;
-
-  fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-  fence_info.pNext = NULL;
-  fence_info.flags = 0;
-
-  err = vkCreateFence (device->device, &fence_info, NULL, fence);
-  if (gst_vulkan_error_to_g_error (err, error, "vkCreateFence") < 0)
-    return FALSE;
-
-  return TRUE;
-}
-
-static gboolean
 _swapper_set_image_layout (GstVulkanSwapper * swapper,
     GstVulkanImageMemory * image, VkImageLayout new_image_layout,
     GError ** error)
 {
-  VkCommandBuffer cmd;
-  VkFence fence;
+  VkCommandBuffer cmd = VK_NULL_HANDLE;
+  GstVulkanFence *fence = NULL;
   VkResult err;
 
   if (!gst_vulkan_device_create_cmd_buffer (swapper->device, &cmd, error))
-    return FALSE;
+    goto error;
 
-  if (!_new_fence (swapper->device, &fence, error))
-    return FALSE;
+  fence = gst_vulkan_fence_new (swapper->device, 0, error);
+  if (!fence)
+    goto error;
 
   {
     VkCommandBufferInheritanceInfo buf_inh = { 0, };
@@ -539,16 +530,16 @@ _swapper_set_image_layout (GstVulkanSwapper * swapper,
 
     err = vkBeginCommandBuffer (cmd, &cmd_buf_info);
     if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
-      return FALSE;
+      goto error;
   }
 
   if (!_swapper_set_image_layout_with_cmd (swapper, cmd, image,
           new_image_layout, error))
-    return FALSE;
+    goto error;
 
   err = vkEndCommandBuffer (cmd);
   if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
-    return FALSE;
+    goto error;
 
   {
     VkSubmitInfo submit_info = { 0, };
@@ -564,20 +555,23 @@ _swapper_set_image_layout (GstVulkanSwapper * swapper,
     submit_info.signalSemaphoreCount = 0;
     submit_info.pSignalSemaphores = NULL;
 
-    err = vkQueueSubmit (swapper->queue->queue, 1, &submit_info, fence);
+    err =
+        vkQueueSubmit (swapper->queue->queue, 1, &submit_info,
+        GST_VULKAN_FENCE_FENCE (fence));
     if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0)
-      return FALSE;
+      goto error;
   }
 
-  err = vkWaitForFences (swapper->device->device, 1, &fence, TRUE, -1);
-  if (gst_vulkan_error_to_g_error (err, error, "vkWaitForFences") < 0)
-    return FALSE;
-  vkFreeCommandBuffers (swapper->device->device, swapper->device->cmd_pool, 1,
-      &cmd);
-
-  vkDestroyFence (swapper->device->device, fence, NULL);
+  swapper->priv->trash_list = g_list_prepend (swapper->priv->trash_list,
+      gst_vulkan_trash_new_free_command_buffer (fence, cmd));
+  fence = NULL;
 
   return TRUE;
+
+error:
+  if (fence)
+    gst_vulkan_fence_unref (fence);
+  return FALSE;
 }
 
 static gboolean
@@ -645,8 +639,8 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
     n_images_wanted = swapper->surf_props.maxImageCount;
   }
 
-  if (swapper->
-      surf_props.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
+  if (swapper->surf_props.
+      supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
     preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
   } else {
     preTransform = swapper->surf_props.currentTransform;
@@ -677,8 +671,8 @@ _allocate_swapchain (GstVulkanSwapper * swapper, GstCaps * caps,
         "Incorrect usage flags available for the swap images");
     return FALSE;
   }
-  if ((swapper->surf_props.
-          supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+  if ((swapper->
+          surf_props.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
       != 0) {
     usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
   } else {
@@ -796,16 +790,9 @@ gst_vulkan_swapper_set_caps (GstVulkanSwapper * swapper, GstCaps * caps,
   return _swapchain_resize (swapper, error);
 }
 
-struct cmd_data
-{
-  VkCommandBuffer cmd;
-  GDestroyNotify notify;
-  gpointer data;
-};
-
 static gboolean
 _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
-    GstBuffer * buffer, struct cmd_data *cmd_data, GError ** error)
+    GstBuffer * buffer, VkCommandBuffer * cmd_ret, GError ** error)
 {
   GstVulkanBufferMemory *buf_mem;
   GstVulkanImageMemory *swap_mem;
@@ -815,8 +802,6 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
   g_return_val_if_fail (swap_idx < swapper->n_swap_chain_images, FALSE);
   swap_mem = swapper->swap_chain_images[swap_idx];
 
-  cmd_data->notify = NULL;
-
   if (!gst_vulkan_device_create_cmd_buffer (swapper->device, &cmd, error))
     return FALSE;
 
@@ -885,8 +870,7 @@ _build_render_buffer_cmd (GstVulkanSwapper * swapper, guint32 swap_idx,
   if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
     return FALSE;
 
-  cmd_data->cmd = cmd;
-  cmd_data->notify = NULL;
+  *cmd_ret = cmd;
 
   return TRUE;
 }
@@ -898,10 +882,14 @@ _render_buffer_unlocked (GstVulkanSwapper * swapper,
   VkSemaphore acquire_semaphore = { 0, };
   VkSemaphore present_semaphore = { 0, };
   VkSemaphoreCreateInfo semaphore_info = { 0, };
+  GstVulkanFence *fence = NULL;
   VkPresentInfoKHR present;
-  struct cmd_data cmd_data = { 0, };
+  VkCommandBuffer cmd = VK_NULL_HANDLE;
   guint32 swap_idx;
-  VkResult err, present_err;
+  VkResult err, present_err = VK_SUCCESS;
+
+  swapper->priv->trash_list =
+      gst_vulkan_trash_list_gc (swapper->priv->trash_list);
 
   semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
   semaphore_info.pNext = NULL;
@@ -943,7 +931,7 @@ reacquire:
     goto error;
   }
 
-  if (!_build_render_buffer_cmd (swapper, swap_idx, buffer, &cmd_data, error))
+  if (!_build_render_buffer_cmd (swapper, swap_idx, buffer, &cmd, error))
     goto error;
 
   err = vkCreateSemaphore (swapper->device->device, &semaphore_info,
@@ -961,14 +949,28 @@ reacquire:
     submit_info.pWaitSemaphores = &acquire_semaphore;
     submit_info.pWaitDstStageMask = &stages;
     submit_info.commandBufferCount = 1;
-    submit_info.pCommandBuffers = &cmd_data.cmd;
+    submit_info.pCommandBuffers = &cmd;
     submit_info.signalSemaphoreCount = 1;
     submit_info.pSignalSemaphores = &present_semaphore;
 
-    err = vkQueueSubmit (swapper->queue->queue, 1, &submit_info, NULL);
-    if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0) {
+    fence = gst_vulkan_fence_new (swapper->device, 0, error);
+    if (!fence)
       goto error;
-    }
+
+    err =
+        vkQueueSubmit (swapper->queue->queue, 1, &submit_info,
+        GST_VULKAN_FENCE_FENCE (fence));
+    if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0)
+      goto error;
+
+    swapper->priv->trash_list = g_list_prepend (swapper->priv->trash_list,
+        gst_vulkan_trash_new_free_command_buffer (gst_vulkan_fence_ref (fence),
+            cmd));
+    swapper->priv->trash_list = g_list_prepend (swapper->priv->trash_list,
+        gst_vulkan_trash_new_free_semaphore (fence, acquire_semaphore));
+
+    cmd = VK_NULL_HANDLE;
+    fence = NULL;
   }
 
   present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@@ -992,19 +994,28 @@ reacquire:
   } else if (gst_vulkan_error_to_g_error (err, error, "vkQueuePresentKHR") < 0)
     goto error;
 
-  err = vkDeviceWaitIdle (swapper->device->device);
-  if (gst_vulkan_error_to_g_error (err, error, "vkDeviceWaitIdle") < 0)
-    goto error;
+  {
+    VkSubmitInfo submit_info = { 0, };
+    VkPipelineStageFlags stages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pWaitDstStageMask = &stages;
+
+    fence = gst_vulkan_fence_new (swapper->device, 0, error);
+    if (!fence)
+      goto error;
+
+    err =
+        vkQueueSubmit (swapper->queue->queue, 1, &submit_info,
+        GST_VULKAN_FENCE_FENCE (fence));
+    if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0)
+      goto error;
+
+    swapper->priv->trash_list = g_list_prepend (swapper->priv->trash_list,
+        gst_vulkan_trash_new_free_semaphore (fence, present_semaphore));
+    fence = NULL;
+  }
 
-  if (acquire_semaphore)
-    vkDestroySemaphore (swapper->device->device, acquire_semaphore, NULL);
-  if (present_semaphore)
-    vkDestroySemaphore (swapper->device->device, present_semaphore, NULL);
-  if (cmd_data.cmd)
-    vkFreeCommandBuffers (swapper->device->device, swapper->device->cmd_pool,
-        1, &cmd_data.cmd);
-  if (cmd_data.notify)
-    cmd_data.notify (cmd_data.data);
   return TRUE;
 
 error:
@@ -1013,11 +1024,9 @@ error:
       vkDestroySemaphore (swapper->device->device, acquire_semaphore, NULL);
     if (present_semaphore)
       vkDestroySemaphore (swapper->device->device, present_semaphore, NULL);
-    if (cmd_data.cmd)
+    if (cmd)
       vkFreeCommandBuffers (swapper->device->device, swapper->device->cmd_pool,
-          1, &cmd_data.cmd);
-    if (cmd_data.notify)
-      cmd_data.notify (cmd_data.data);
+          1, &cmd);
     return FALSE;
   }
 }