vulkan: fix up some gir annotations
[platform/upstream/gstreamer.git] / gst-libs / gst / vulkan / gstvktrash.c
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 "gstvktrash.h"
26 #include "gstvkhandle.h"
27
28 GST_DEBUG_CATEGORY (gst_debug_vulkan_trash);
29 #define GST_CAT_DEFAULT gst_debug_vulkan_trash
30
31 #define gst_vulkan_trash_release(c,t) \
32     gst_vulkan_handle_pool_release (GST_VULKAN_HANDLE_POOL_CAST (c), t);
33
34 static void
35 _init_debug (void)
36 {
37   static volatile gsize init;
38
39   if (g_once_init_enter (&init)) {
40     GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_trash,
41         "vulkantrash", 0, "Vulkan Trash");
42     g_once_init_leave (&init, 1);
43   }
44 }
45
46 static gboolean
47 gst_vulkan_trash_dispose (GstVulkanTrash * trash)
48 {
49   GstVulkanTrashList *cache;
50
51   /* no pool, do free */
52   if ((cache = trash->cache) == NULL)
53     return TRUE;
54
55   /* keep the buffer alive */
56   gst_vulkan_trash_ref (trash);
57   /* return the trash object to the pool */
58   gst_vulkan_trash_release (cache, trash);
59
60   return FALSE;
61 }
62
63 static void
64 gst_vulkan_trash_deinit (GstVulkanTrash * trash)
65 {
66   if (trash->fence) {
67     g_warn_if_fail (gst_vulkan_fence_is_signaled (trash->fence));
68     gst_vulkan_fence_unref (trash->fence);
69     trash->fence = NULL;
70   }
71
72   trash->notify = NULL;
73   trash->user_data = NULL;
74 }
75
76 static void
77 gst_vulkan_trash_free (GstMiniObject * object)
78 {
79   GstVulkanTrash *trash = (GstVulkanTrash *) object;
80
81   GST_TRACE ("Freeing trash object %p with fence %" GST_PTR_FORMAT, trash,
82       trash->fence);
83
84   gst_vulkan_trash_deinit (trash);
85
86   g_free (trash);
87 }
88
89 static void
90 gst_vulkan_trash_init (GstVulkanTrash * trash, GstVulkanFence * fence,
91     GstVulkanTrashNotify notify, gpointer user_data)
92 {
93   g_return_if_fail (fence != NULL);
94   g_return_if_fail (GST_IS_VULKAN_DEVICE (fence->device));
95   g_return_if_fail (notify != NULL);
96
97   gst_mini_object_init ((GstMiniObject *) trash, 0,
98       gst_vulkan_trash_get_type (), NULL,
99       (GstMiniObjectDisposeFunction) gst_vulkan_trash_dispose,
100       (GstMiniObjectFreeFunction) gst_vulkan_trash_free);
101   GST_TRACE ("Initializing trash object %p with fence %" GST_PTR_FORMAT
102       " on device %" GST_PTR_FORMAT, trash, fence, fence->device);
103   trash->fence = gst_vulkan_fence_ref (fence);
104   trash->notify = notify;
105   trash->user_data = user_data;
106 }
107
108 /**
109  * gst_vulkan_trash_new:
110  * @fence: a #GstVulkanFence
111  * @notify: (scope async): a #GstVulkanTrashNotify
112  * @user_data: (closure notify): user data for @notify
113  *
114  * Create and return a new #GstVulkanTrash object that will stores a callback
115  * to call when @fence is signalled.
116  *
117  * Returns: (transfer full): a new #GstVulkanTrash
118  */
119 GstVulkanTrash *
120 gst_vulkan_trash_new (GstVulkanFence * fence, GstVulkanTrashNotify notify,
121     gpointer user_data)
122 {
123   GstVulkanTrash *ret = NULL;
124
125   g_return_val_if_fail (fence != NULL, NULL);
126   g_return_val_if_fail (GST_IS_VULKAN_DEVICE (fence->device), NULL);
127   g_return_val_if_fail (notify != NULL, NULL);
128
129   _init_debug ();
130
131   ret = g_new0 (GstVulkanTrash, 1);
132   GST_TRACE ("Creating new trash object %p with fence %" GST_PTR_FORMAT
133       " on device %" GST_PTR_FORMAT, ret, fence, fence->device);
134   gst_vulkan_trash_init (ret, fence, notify, user_data);
135
136   return ret;
137 }
138
139 #if GLIB_SIZEOF_VOID_P == 8
140 # define PUSH_NON_DISPATCHABLE_HANDLE_TO_GPOINTER(pointer, handle) pointer = (gpointer) handle
141 # define TAKE_NON_DISPATCHABLE_HANDLE_FROM_GPOINTER(handle, type, pointer) handle = (type) pointer
142 #else
143 # define PUSH_NON_DISPATCHABLE_HANDLE_TO_GPOINTER(pointer, handle) \
144     G_STMT_START { \
145       pointer = g_new0(guint64, 1); \
146       *((GstVulkanHandleTypedef *) pointer) = (GstVulkanHandleTypedef) handle; \
147     } G_STMT_END
148 # define TAKE_NON_DISPATCHABLE_HANDLE_FROM_GPOINTER(handle, type, pointer) \
149     G_STMT_START { \
150       handle = *((type *) pointer); \
151       g_free (pointer); \
152     } G_STMT_END
153 #endif
154
155 #define FREE_DESTROY_FUNC(func, type, type_name) \
156 static void \
157 G_PASTE(_free_,type_name) (GstVulkanDevice * device, gpointer resource_handle) \
158 { \
159   type resource; \
160   TAKE_NON_DISPATCHABLE_HANDLE_FROM_GPOINTER(resource, type, resource_handle); \
161   GST_TRACE_OBJECT (device, "Freeing vulkan " G_STRINGIFY (type) \
162       " %" GST_VULKAN_NON_DISPATCHABLE_HANDLE_FORMAT, resource); \
163   func (device->device, resource, NULL); \
164 } \
165 GstVulkanTrash * \
166 G_PASTE(gst_vulkan_trash_new_free_,type_name) (GstVulkanFence * fence, \
167     type type_name) \
168 { \
169   GstVulkanTrash *trash; \
170   gpointer handle_data; \
171   PUSH_NON_DISPATCHABLE_HANDLE_TO_GPOINTER(handle_data, type_name); \
172   g_return_val_if_fail (type_name != VK_NULL_HANDLE, VK_NULL_HANDLE); \
173   trash = gst_vulkan_trash_new (fence, \
174       (GstVulkanTrashNotify) G_PASTE(_free_,type_name), handle_data); \
175   return trash; \
176 }
177
178 FREE_DESTROY_FUNC (vkDestroySemaphore, VkSemaphore, semaphore);
179 #define FREE_WITH_VK_PARENT(func, type, type_name, parent_type) \
180 struct G_PASTE(free_parent_info_,type_name) \
181 { \
182   parent_type parent; \
183   type resource; \
184 }; \
185 static void \
186 G_PASTE(_free_,type_name) (GstVulkanDevice * device, struct G_PASTE(free_parent_info_,type_name) *info) \
187 { \
188   GST_TRACE_OBJECT (device, "Freeing vulkan " G_STRINGIFY (type) \
189       " %" GST_VULKAN_NON_DISPATCHABLE_HANDLE_FORMAT, info->resource); \
190   func (device->device, info->parent, 1, &info->resource); \
191   g_free (info); \
192 } \
193 GstVulkanTrash * \
194 G_PASTE(gst_vulkan_trash_new_free_,type_name) (GstVulkanFence * fence, \
195     parent_type parent, type type_name) \
196 { \
197   struct G_PASTE(free_parent_info_,type_name) *info; \
198   GstVulkanTrash *trash; \
199   g_return_val_if_fail (type_name != VK_NULL_HANDLE, VK_NULL_HANDLE); \
200   info = g_new0 (struct G_PASTE(free_parent_info_,type_name), 1); \
201   /* FIXME: keep parent alive ? */\
202   info->parent = parent; \
203   info->resource = type_name; \
204   trash = gst_vulkan_trash_new (fence, \
205       (GstVulkanTrashNotify) G_PASTE(_free_,type_name), info); \
206   return trash; \
207 }
208
209 void
210 gst_vulkan_trash_object_unref (GstVulkanDevice * device, gpointer user_data)
211 {
212   gst_object_unref ((GstObject *) user_data);
213 }
214
215 void
216 gst_vulkan_trash_mini_object_unref (GstVulkanDevice * device,
217     gpointer user_data)
218 {
219   gst_mini_object_unref ((GstMiniObject *) user_data);
220 }
221
222 G_DEFINE_TYPE_WITH_CODE (GstVulkanTrashList, gst_vulkan_trash_list,
223     GST_TYPE_VULKAN_HANDLE_POOL, _init_debug ());
224
225 void
226 gst_vulkan_trash_list_gc (GstVulkanTrashList * trash_list)
227 {
228   GstVulkanTrashListClass *trash_class;
229   g_return_if_fail (GST_IS_VULKAN_TRASH_LIST (trash_list));
230   trash_class = GST_VULKAN_TRASH_LIST_GET_CLASS (trash_list);
231   g_return_if_fail (trash_class->gc_func != NULL);
232
233   trash_class->gc_func (trash_list);
234 }
235
236 gboolean
237 gst_vulkan_trash_list_add (GstVulkanTrashList * trash_list,
238     GstVulkanTrash * trash)
239 {
240   GstVulkanTrashListClass *trash_class;
241   g_return_val_if_fail (GST_IS_VULKAN_TRASH_LIST (trash_list), FALSE);
242   trash_class = GST_VULKAN_TRASH_LIST_GET_CLASS (trash_list);
243   g_return_val_if_fail (trash_class->add_func != NULL, FALSE);
244
245   return trash_class->add_func (trash_list, trash);
246 }
247
248 gboolean
249 gst_vulkan_trash_list_wait (GstVulkanTrashList * trash_list, guint64 timeout)
250 {
251   GstVulkanTrashListClass *trash_class;
252   g_return_val_if_fail (GST_IS_VULKAN_TRASH_LIST (trash_list), FALSE);
253   trash_class = GST_VULKAN_TRASH_LIST_GET_CLASS (trash_list);
254   g_return_val_if_fail (trash_class->wait_func != NULL, FALSE);
255
256   return trash_class->wait_func (trash_list, timeout);
257 }
258
259 static gpointer
260 gst_vulkan_trash_list_alloc_impl (GstVulkanHandlePool * pool, GError ** error)
261 {
262   return g_new0 (GstVulkanTrash, 1);
263 }
264
265 static void
266 gst_vulkan_trash_list_release_impl (GstVulkanHandlePool * pool, gpointer handle)
267 {
268   GstVulkanTrash *trash = handle;
269
270   GST_TRACE_OBJECT (pool, "reset trash object %p", trash);
271
272   gst_vulkan_trash_deinit (trash);
273   gst_clear_object (&trash->cache);
274
275   GST_VULKAN_HANDLE_POOL_CLASS (gst_vulkan_trash_list_parent_class)->release
276       (pool, handle);
277 }
278
279 static void
280 gst_vulkan_trash_list_free_impl (GstVulkanHandlePool * pool, gpointer handle)
281 {
282   GstVulkanTrash *trash = handle;
283
284   gst_vulkan_trash_unref (trash);
285 }
286
287 static void
288 gst_vulkan_trash_list_class_init (GstVulkanTrashListClass * klass)
289 {
290   GstVulkanHandlePoolClass *pool_class = (GstVulkanHandlePoolClass *) klass;
291
292   pool_class->alloc = gst_vulkan_trash_list_alloc_impl;
293   pool_class->release = gst_vulkan_trash_list_release_impl;
294   pool_class->free = gst_vulkan_trash_list_free_impl;
295 }
296
297 static void
298 gst_vulkan_trash_list_init (GstVulkanTrashList * trash_list)
299 {
300 }
301
302 /**
303  * gst_vulkan_trash_list_acquire:
304  * @trash_list: a #GstVulkanTrashList
305  * @fence: a #GstVulkanFence to wait for signalling
306  * @notify: (scope async): notify function for when @fence is signalled
307  * @user_data: user data for @notify
308  *
309  * Returns: (transfer full): a new or reused #GstVulkanTrash for the provided
310  *          parameters.
311  */
312 GstVulkanTrash *
313 gst_vulkan_trash_list_acquire (GstVulkanTrashList * trash_list,
314     GstVulkanFence * fence, GstVulkanTrashNotify notify, gpointer user_data)
315 {
316   GstVulkanHandlePool *pool = GST_VULKAN_HANDLE_POOL (trash_list);
317   GstVulkanHandlePoolClass *pool_class;
318   GstVulkanTrash *trash;
319
320   g_return_val_if_fail (GST_IS_VULKAN_TRASH_LIST (trash_list), NULL);
321
322   pool_class = GST_VULKAN_HANDLE_POOL_GET_CLASS (trash_list);
323
324   trash = pool_class->acquire (pool, NULL);
325   gst_vulkan_trash_init (trash, fence, notify, user_data);
326   trash->cache = gst_object_ref (trash_list);
327
328   GST_TRACE_OBJECT (trash_list, "acquired trash object %p", trash);
329
330   return trash;
331 }
332
333 typedef struct _GstVulkanTrashFenceList GstVulkanTrashFenceList;
334
335 struct _GstVulkanTrashFenceList
336 {
337   GstVulkanTrashList parent;
338
339   GList *list;
340 };
341
342 G_DEFINE_TYPE (GstVulkanTrashFenceList, gst_vulkan_trash_fence_list,
343     GST_TYPE_VULKAN_TRASH_LIST);
344
345 static void
346 gst_vulkan_trash_fence_list_gc (GstVulkanTrashList * trash_list)
347 {
348   GstVulkanTrashFenceList *fence_list = (GstVulkanTrashFenceList *) trash_list;
349   GList *l = fence_list->list;
350
351   while (l) {
352     GstVulkanTrash *trash = l->data;
353
354     if (gst_vulkan_fence_is_signaled (trash->fence)) {
355       GList *next = g_list_next (l);
356       GST_TRACE_OBJECT (fence_list, "fence %" GST_PTR_FORMAT " has been "
357           "signalled, notifying", trash->fence);
358       trash->notify (trash->fence->device, trash->user_data);
359       gst_vulkan_trash_unref (trash);
360       fence_list->list = g_list_delete_link (fence_list->list, l);
361       l = next;
362     } else {
363       l = g_list_next (l);
364     }
365   }
366 }
367
368 static gboolean
369 gst_vulkan_trash_fence_list_wait (GstVulkanTrashList * trash_list,
370     guint64 timeout)
371 {
372   GstVulkanTrashFenceList *fence_list = (GstVulkanTrashFenceList *) trash_list;
373   VkResult err = VK_SUCCESS;
374   guint i, n;
375
376   /* remove all the previously signaled fences */
377   gst_vulkan_trash_fence_list_gc (trash_list);
378
379   n = g_list_length (fence_list->list);
380   if (n > 0) {
381     VkFence *fences;
382     GstVulkanDevice *device = NULL;
383     GList *l = NULL;
384
385     fences = g_new0 (VkFence, n);
386     for (i = 0, l = fence_list->list; i < n; i++, l = g_list_next (l)) {
387       GstVulkanTrash *trash = l->data;
388
389       if (device == NULL)
390         device = trash->fence->device;
391
392       fences[i] = trash->fence->fence;
393
394       /* only support waiting on fences from the same device */
395       g_assert (device == trash->fence->device);
396     }
397
398     GST_TRACE_OBJECT (trash_list, "Waiting on %d fences with timeout %"
399         GST_TIME_FORMAT, n, GST_TIME_ARGS (timeout));
400     err = vkWaitForFences (device->device, n, fences, TRUE, timeout);
401     g_free (fences);
402
403     gst_vulkan_trash_fence_list_gc (trash_list);
404   }
405
406   return err == VK_SUCCESS;
407 }
408
409 static gboolean
410 gst_vulkan_trash_fence_list_add (GstVulkanTrashList * trash_list,
411     GstVulkanTrash * trash)
412 {
413   GstVulkanTrashFenceList *fence_list = (GstVulkanTrashFenceList *) trash_list;
414
415   g_return_val_if_fail (GST_MINI_OBJECT_TYPE (trash) == GST_TYPE_VULKAN_TRASH,
416       FALSE);
417
418   /* XXX: do something better based on the actual fence */
419   fence_list->list = g_list_prepend (fence_list->list, trash);
420
421   return TRUE;
422 }
423
424 static void
425 gst_vulkan_trash_fence_list_finalize (GObject * object)
426 {
427   GstVulkanTrashList *trash_list = (GstVulkanTrashList *) object;
428   GstVulkanTrashFenceList *fence_list = (GstVulkanTrashFenceList *) object;
429
430   gst_vulkan_trash_fence_list_gc (trash_list);
431   g_warn_if_fail (fence_list->list == NULL);
432
433   G_OBJECT_CLASS (gst_vulkan_trash_fence_list_parent_class)->finalize (object);
434 }
435
436 static void
437 gst_vulkan_trash_fence_list_class_init (GstVulkanTrashFenceListClass * klass)
438 {
439   GstVulkanTrashListClass *trash_class = (GstVulkanTrashListClass *) klass;
440   GObjectClass *object_class = (GObjectClass *) klass;
441
442   trash_class->add_func = gst_vulkan_trash_fence_list_add;
443   trash_class->gc_func = gst_vulkan_trash_fence_list_gc;
444   trash_class->wait_func = gst_vulkan_trash_fence_list_wait;
445
446   object_class->finalize = gst_vulkan_trash_fence_list_finalize;
447 }
448
449 static void
450 gst_vulkan_trash_fence_list_init (GstVulkanTrashFenceList * trash_list)
451 {
452 }
453
454 GstVulkanTrashList *
455 gst_vulkan_trash_fence_list_new (void)
456 {
457   return g_object_new (gst_vulkan_trash_fence_list_get_type (), NULL);
458 }
459
460 GST_DEFINE_MINI_OBJECT_TYPE (GstVulkanTrash, gst_vulkan_trash);