1 /*
2  * GStreamer
3  * Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "vktrash.h"
26 #include "vkutils_private.h"
27 
28 GST_DEBUG_CATEGORY (gst_debug_vulkan_trash);
29 #define GST_CAT_DEFAULT gst_debug_vulkan_trash
30 
31 static void
_init_debug(void)32 _init_debug (void)
33 {
34   static volatile gsize init;
35 
36   if (g_once_init_enter (&init)) {
37     GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_trash,
38         "vulkantrash", 0, "Vulkan Trash");
39     g_once_init_leave (&init, 1);
40   }
41 }
42 
43 void
gst_vulkan_trash_free(GstVulkanTrash * trash)44 gst_vulkan_trash_free (GstVulkanTrash * trash)
45 {
46   if (!trash)
47     return;
48 
49   GST_TRACE ("Freeing trash object %p with fence %" GST_PTR_FORMAT, trash,
50       trash->fence);
51 
52   gst_vulkan_fence_unref (trash->fence);
53 
54   g_free (trash);
55 }
56 
57 GstVulkanTrash *
gst_vulkan_trash_new(GstVulkanFence * fence,GstVulkanTrashNotify notify,gpointer user_data)58 gst_vulkan_trash_new (GstVulkanFence * fence, GstVulkanTrashNotify notify,
59     gpointer user_data)
60 {
61   GstVulkanTrash *ret = NULL;
62 
63   g_return_val_if_fail (fence != NULL, NULL);
64   g_return_val_if_fail (GST_IS_VULKAN_DEVICE (fence->device), NULL);
65   g_return_val_if_fail (notify != NULL, NULL);
66 
67   _init_debug ();
68 
69   ret = g_new0 (GstVulkanTrash, 1);
70   GST_TRACE ("Creating new trash object %p with fence %" GST_PTR_FORMAT
71       " on device %" GST_PTR_FORMAT, ret, fence, fence->device);
72   ret->fence = fence;
73   ret->notify = notify;
74   ret->user_data = user_data;
75 
76   return ret;
77 }
78 
79 GList *
gst_vulkan_trash_list_gc(GList * trash_list)80 gst_vulkan_trash_list_gc (GList * trash_list)
81 {
82   GList *l = trash_list;
83 
84   while (l) {
85     GstVulkanTrash *trash = l->data;
86 
87     if (gst_vulkan_fence_is_signaled (trash->fence)) {
88       GList *next = g_list_next (l);
89       GST_TRACE ("fence %" GST_PTR_FORMAT " has been signalled, notifying",
90           trash->fence);
91       trash->notify (trash->fence->device, trash->user_data);
92       gst_vulkan_trash_free (trash);
93       trash_list = g_list_delete_link (trash_list, l);
94       l = next;
95     } else {
96       l = g_list_next (l);
97     }
98   }
99 
100   return trash_list;
101 }
102 
103 gboolean
gst_vulkan_trash_list_wait(GList * trash_list,guint64 timeout)104 gst_vulkan_trash_list_wait (GList * trash_list, guint64 timeout)
105 {
106   VkResult err = VK_SUCCESS;
107   guint i, n;
108 
109   /* remove all the previously signaled fences */
110   trash_list = gst_vulkan_trash_list_gc (trash_list);
111 
112   n = g_list_length (trash_list);
113   if (n > 0) {
114     VkFence *fences;
115     GstVulkanDevice *device = NULL;
116     GList *l = NULL;
117 
118     fences = g_new0 (VkFence, n);
119     for (i = 0, l = trash_list; i < n; i++, l = g_list_next (l)) {
120       GstVulkanTrash *trash = l->data;
121 
122       if (device == NULL)
123         device = trash->fence->device;
124 
125       fences[i] = trash->fence->fence;
126 
127       /* only support waiting on fences from the same device */
128       g_assert (device == trash->fence->device);
129     }
130 
131     GST_TRACE ("Waiting on %d fences with timeout %" GST_TIME_FORMAT, n,
132         GST_TIME_ARGS (timeout));
133     err = vkWaitForFences (device->device, n, fences, TRUE, timeout);
134     g_free (fences);
135 
136     trash_list = gst_vulkan_trash_list_gc (trash_list);
137   }
138 
139   return err == VK_SUCCESS;
140 }
141 
142 static void
_free_command_buffer(GstVulkanDevice * device,VkCommandBuffer * cmd)143 _free_command_buffer (GstVulkanDevice * device, VkCommandBuffer * cmd)
144 {
145   g_assert (cmd);
146   vkFreeCommandBuffers (device->device, device->cmd_pool, 1, cmd);
147 
148   g_free (cmd);
149 }
150 
151 GstVulkanTrash *
gst_vulkan_trash_new_free_command_buffer(GstVulkanFence * fence,VkCommandBuffer cmd)152 gst_vulkan_trash_new_free_command_buffer (GstVulkanFence * fence,
153     VkCommandBuffer cmd)
154 {
155   VkCommandBuffer *data;
156   GstVulkanTrash *trash;
157 
158   data = g_new0 (VkCommandBuffer, 1);
159   *data = cmd;
160   trash = gst_vulkan_trash_new (fence,
161       (GstVulkanTrashNotify) _free_command_buffer, data);
162 
163   return trash;
164 }
165 
166 static void
_free_semaphore(GstVulkanDevice * device,VkSemaphore * semaphore)167 _free_semaphore (GstVulkanDevice * device, VkSemaphore * semaphore)
168 {
169   if (semaphore)
170     vkDestroySemaphore (device->device, *semaphore, NULL);
171 
172   g_free (semaphore);
173 }
174 
175 GstVulkanTrash *
gst_vulkan_trash_new_free_semaphore(GstVulkanFence * fence,VkSemaphore semaphore)176 gst_vulkan_trash_new_free_semaphore (GstVulkanFence * fence,
177     VkSemaphore semaphore)
178 {
179   VkSemaphore *data;
180   GstVulkanTrash *trash;
181 
182   data = g_new0 (VkSemaphore, 1);
183   *data = semaphore;
184   trash = gst_vulkan_trash_new (fence,
185       (GstVulkanTrashNotify) _free_semaphore, data);
186 
187   return trash;
188 }
189