1 /*
2  * GStreamer
3  * Copyright (C) 2015 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 <string.h>
26 
27 #include "gstglbasememory.h"
28 
29 #include "gstglcontext.h"
30 #include "gstglcontext_private.h"
31 #include "gstglquery.h"
32 
33 /**
34  * SECTION:gstglbasememory
35  * @title: GstGLBaseMemory
36  * @short_description: memory subclass for GL buffers
37  * @see_also: #GstMemory, #GstAllocator
38  *
39  * GstGLBaseMemory is a #GstMemory subclass providing the basis of support
40  * for the mapping of GL buffers.
41  *
42  * Data is uploaded or downloaded from the GPU as is necessary.
43  */
44 
45 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
46 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
47 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
48 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
49 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
50 
51 GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_BASE_MEMORY);
52 #define GST_CAT_DEFUALT GST_CAT_GL_BASE_MEMORY
53 
54 GST_DEFINE_MINI_OBJECT_TYPE (GstGLBaseMemory, gst_gl_base_memory);
55 
56 GQuark
gst_gl_base_memory_error_quark(void)57 gst_gl_base_memory_error_quark (void)
58 {
59   return g_quark_from_static_string ("gst-gl-base-memory-error-quark");
60 }
61 
62 static gboolean
_default_create(GstGLBaseMemory * mem,GError ** error)63 _default_create (GstGLBaseMemory * mem, GError ** error)
64 {
65   g_set_error (error, GST_GL_BASE_MEMORY_ERROR, GST_GL_BASE_MEMORY_ERROR_FAILED,
66       "subclass should define create() vfunc");
67 
68   g_critical ("subclass should override "
69       "GstGLBaseMemoryAllocatorClass::create() function");
70 
71   return FALSE;
72 }
73 
74 struct create_data
75 {
76   GstGLBaseMemory *mem;
77   gboolean result;
78 };
79 
80 static void
_mem_create_gl(GstGLContext * context,struct create_data * transfer)81 _mem_create_gl (GstGLContext * context, struct create_data *transfer)
82 {
83   GstGLBaseMemoryAllocatorClass *alloc_class;
84   GError *error = NULL;
85 
86   GST_CAT_TRACE (GST_CAT_GL_BASE_MEMORY, "Create memory %p", transfer->mem);
87 
88   alloc_class =
89       GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (transfer->mem->mem.allocator);
90 
91   g_return_if_fail (alloc_class->create != NULL);
92 
93   /* Don't do expensive queries when debugging is disabled */
94   transfer->mem->query = NULL;
95   if (_gst_gl_context_debug_is_enabled (context))
96     transfer->mem->query =
97         gst_gl_query_new (context, GST_GL_QUERY_TIME_ELAPSED);
98 
99   if ((transfer->result = alloc_class->create (transfer->mem, &error)))
100     return;
101 
102   g_assert (error != NULL);
103 
104   GST_CAT_ERROR (GST_CAT_GL_BASE_MEMORY, "Failed to create GL buffer: %s",
105       error->message);
106   g_clear_error (&error);
107 }
108 
109 /**
110  * gst_gl_base_memory_init:
111  * @mem: the #GstGLBaseMemory to initialize
112  * @allocator: the #GstAllocator to initialize with
113  * @parent: (allow-none): the parent #GstMemory to initialize with
114  * @context: the #GstGLContext to initialize with
115  * @params: (allow-none): the @GstAllocationParams to initialize with
116  * @size: the number of bytes to be allocated
117  * @user_data: (allow-none): user data to call @notify with
118  * @notify: (allow-none): a #GDestroyNotify
119  *
120  * Initializes @mem with the required parameters
121  *
122  * Since: 1.8
123  */
124 void
gst_gl_base_memory_init(GstGLBaseMemory * mem,GstAllocator * allocator,GstMemory * parent,GstGLContext * context,GstAllocationParams * params,gsize size,gpointer user_data,GDestroyNotify notify)125 gst_gl_base_memory_init (GstGLBaseMemory * mem, GstAllocator * allocator,
126     GstMemory * parent, GstGLContext * context, GstAllocationParams * params,
127     gsize size, gpointer user_data, GDestroyNotify notify)
128 {
129   gsize align = gst_memory_alignment, offset = 0, maxsize;
130   GstMemoryFlags flags = 0;
131   struct create_data data;
132 
133   /* A note on sizes.
134    * gl_mem->alloc_size: the size to allocate when we control the allocation.
135    *                     Size of the unaligned allocation.
136    * mem->maxsize: the size that is used by GstMemory for mapping, to map the
137    *               entire memory. The size of the aligned allocation
138    * mem->size: represents the size of the valid data. Can be reduced with
139    *            gst_memory_resize()
140    *
141    * It holds that:
142    * mem->size + mem->offset <= mem->maxsize
143    * and
144    * mem->maxsize + alignment offset <= gl_mem->alloc_size
145    *
146    * We need to add the alignment mask to the allocated size in order to have
147    * the freedom to align the gl_mem->data pointer correctly which may be offset
148    * by at most align bytes in the alloc_data pointer.
149    *
150    * maxsize is not suitable for this as it is used by GstMemory as the size
151    * to map with.
152    */
153   mem->alloc_size = maxsize = size;
154   if (params) {
155     flags = params->flags;
156     align |= params->align;
157     offset = params->prefix;
158     maxsize += params->prefix + params->padding;
159 
160     /* deals with any alignment */
161     mem->alloc_size = maxsize + align;
162   }
163 
164   gst_memory_init (GST_MEMORY_CAST (mem), flags, allocator, parent, maxsize,
165       align, offset, size);
166 
167   mem->context = gst_object_ref (context);
168   mem->notify = notify;
169   mem->user_data = user_data;
170 
171   g_mutex_init (&mem->lock);
172 
173   data.mem = mem;
174 
175   gst_gl_context_thread_add (context,
176       (GstGLContextThreadFunc) _mem_create_gl, &data);
177   if (!data.result) {
178     GST_CAT_ERROR (GST_CAT_GL_BASE_MEMORY,
179         "Could not create GL buffer with context:%p", context);
180   }
181 
182   GST_CAT_DEBUG (GST_CAT_GL_BASE_MEMORY, "new GL buffer memory:%p size:%"
183       G_GSIZE_FORMAT, mem, maxsize);
184 }
185 
186 static gpointer
_align_data(gpointer data,gsize align)187 _align_data (gpointer data, gsize align)
188 {
189   guint8 *ret = data;
190   gsize aoffset;
191 
192   /* do alignment, data must have enough padding at the end to move at most
193    * align bytes */
194   if ((aoffset = ((guintptr) ret & align))) {
195     aoffset = (align + 1) - aoffset;
196     ret += aoffset;
197   }
198 
199   return ret;
200 }
201 
202 /* subclass usage only */
203 /**
204  * gst_gl_base_memory_alloc_data:
205  * @gl_mem: a #GstGLBaseMemory
206  *
207  * Note: only intended for subclass usage to allocate the sytem memory buffer
208  * on demand.  If there is already a non-NULL data pointer in @gl_mem->data,
209  * then this function imply returns TRUE.
210  *
211  * Returns: whether the system memory could be allocated
212  */
213 gboolean
gst_gl_base_memory_alloc_data(GstGLBaseMemory * gl_mem)214 gst_gl_base_memory_alloc_data (GstGLBaseMemory * gl_mem)
215 {
216   GstMemory *mem = (GstMemory *) gl_mem;
217 
218   if (gl_mem->data)
219     return TRUE;
220 
221   GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "%p attempting allocation of data "
222       "pointer of size %" G_GSIZE_FORMAT, gl_mem, gl_mem->alloc_size);
223   gl_mem->alloc_data = g_try_malloc (gl_mem->alloc_size);
224 
225   if (gl_mem->alloc_data == NULL)
226     return FALSE;
227 
228   gl_mem->data = _align_data (gl_mem->alloc_data, mem->align);
229 
230   GST_CAT_DEBUG (GST_CAT_GL_BASE_MEMORY, "%p allocated data pointer alloc %p, "
231       "data %p", gl_mem, gl_mem->alloc_data, gl_mem->data);
232 
233   return TRUE;
234 }
235 
236 struct map_data
237 {
238   GstGLBaseMemory *mem;
239   GstMapInfo *info;
240   gsize size;
241   gpointer data;
242 };
243 
244 static void
_map_data_gl(GstGLContext * context,struct map_data * transfer)245 _map_data_gl (GstGLContext * context, struct map_data *transfer)
246 {
247   GstGLBaseMemoryAllocatorClass *alloc_class;
248   GstGLBaseMemory *mem = transfer->mem;
249   GstMapInfo *info = transfer->info;
250   guint prev_map_flags;
251   guint prev_gl_map_count;
252 
253   alloc_class =
254       GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (transfer->mem->mem.allocator);
255 
256   g_return_if_fail (alloc_class->map != NULL);
257 
258   g_mutex_lock (&mem->lock);
259 
260   prev_map_flags = mem->map_flags;
261   prev_gl_map_count = mem->gl_map_count;
262 
263   GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "mapping mem %p flags %04x", mem,
264       info->flags);
265 
266   /* FIXME: validate map flags based on the memory domain */
267   if (mem->map_count++ == 0)
268     mem->map_flags = info->flags;
269   else {
270     /* assert that the flags are a subset of the first map flags */
271     g_assert ((((GST_MAP_GL - 1) & info->flags) & mem->map_flags) != 0);
272     GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "multiple map no %d flags %04x "
273         "all flags %04x", mem->map_count, info->flags, mem->map_flags);
274   }
275 
276   if ((info->flags & GST_MAP_GL) != (mem->map_flags & GST_MAP_GL))
277     mem->map_flags |= GST_MAP_GL;
278 
279   if (info->flags & GST_MAP_GL)
280     mem->gl_map_count++;
281 
282   transfer->data = alloc_class->map (transfer->mem, transfer->info,
283       transfer->size);
284 
285   if (transfer->data) {
286     if (info->flags & GST_MAP_GL) {
287       if (info->flags & GST_MAP_WRITE)
288         GST_MINI_OBJECT_FLAG_SET (mem,
289             GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
290       GST_MEMORY_FLAG_UNSET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
291     } else {
292       if (info->flags & GST_MAP_WRITE)
293         GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
294       GST_MEMORY_FLAG_UNSET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
295     }
296   } else {
297     /* undo state tracking on error */
298     mem->map_flags = prev_map_flags;
299     mem->gl_map_count = prev_gl_map_count;
300     mem->map_count--;
301   }
302 
303   g_mutex_unlock (&mem->lock);
304 }
305 
306 static gpointer
_mem_map_full(GstGLBaseMemory * mem,GstMapInfo * info,gsize size)307 _mem_map_full (GstGLBaseMemory * mem, GstMapInfo * info, gsize size)
308 {
309   struct map_data transfer;
310 
311   transfer.mem = mem;
312   transfer.info = info;
313   transfer.size = size;
314   transfer.data = NULL;
315 
316   gst_gl_context_thread_add (mem->context,
317       (GstGLContextThreadFunc) _map_data_gl, &transfer);
318 
319   return transfer.data;
320 }
321 
322 struct unmap_data
323 {
324   GstGLBaseMemory *mem;
325   GstMapInfo *info;
326 };
327 
328 static void
_unmap_data_gl(GstGLContext * context,struct unmap_data * transfer)329 _unmap_data_gl (GstGLContext * context, struct unmap_data *transfer)
330 {
331   GstGLBaseMemoryAllocatorClass *alloc_class;
332   GstGLBaseMemory *mem = transfer->mem;
333   GstMapInfo *info = transfer->info;
334 
335   alloc_class =
336       GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (transfer->mem->mem.allocator);
337 
338   g_return_if_fail (alloc_class->unmap != NULL);
339 
340   g_mutex_lock (&mem->lock);
341 
342   GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "unmapping mem %p flags %04x", mem,
343       info->flags);
344 
345   alloc_class->unmap (transfer->mem, transfer->info);
346 
347   if (info->flags & GST_MAP_GL && --mem->gl_map_count)
348     /* unset the gl flag */
349     mem->map_flags &= ~GST_MAP_GL;
350 
351   if (--mem->map_count <= 0) {
352     mem->map_flags = 0;
353   }
354 
355   if (info->flags & GST_MAP_GL) {
356     if (info->flags & GST_MAP_WRITE)
357       GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
358   } else {
359     if (info->flags & GST_MAP_WRITE)
360       GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
361   }
362 
363   g_mutex_unlock (&mem->lock);
364 }
365 
366 static void
_mem_unmap_full(GstGLBaseMemory * mem,GstMapInfo * info)367 _mem_unmap_full (GstGLBaseMemory * mem, GstMapInfo * info)
368 {
369   struct unmap_data transfer;
370 
371   transfer.mem = mem;
372   transfer.info = info;
373 
374   gst_gl_context_thread_add (mem->context,
375       (GstGLContextThreadFunc) _unmap_data_gl, &transfer);
376 }
377 
378 static GstGLBaseMemory *
_default_copy(GstGLBaseMemory * src,gssize offset,gssize size)379 _default_copy (GstGLBaseMemory * src, gssize offset, gssize size)
380 {
381   return NULL;
382 }
383 
384 struct copy_params
385 {
386   GstGLBaseMemory *src;
387   GstGLBaseMemory *dest;
388   gssize offset;
389   gssize size;
390   gboolean result;
391 };
392 
393 static void
_mem_copy_gl(GstGLContext * context,struct copy_params * transfer)394 _mem_copy_gl (GstGLContext * context, struct copy_params *transfer)
395 {
396   GstGLBaseMemoryAllocatorClass *alloc_class;
397 
398   alloc_class =
399       GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (transfer->src->mem.allocator);
400 
401   g_return_if_fail (alloc_class->copy != NULL);
402 
403   transfer->dest =
404       alloc_class->copy (transfer->src, transfer->offset, transfer->size);
405 }
406 
407 static GstMemory *
_mem_copy(GstGLBaseMemory * src,gssize offset,gssize size)408 _mem_copy (GstGLBaseMemory * src, gssize offset, gssize size)
409 {
410   struct copy_params transfer;
411 
412   transfer.dest = NULL;
413   transfer.src = src;
414   transfer.offset = offset;
415   transfer.size = size;
416   if (size == -1 || size > 0)
417     gst_gl_context_thread_add (src->context,
418         (GstGLContextThreadFunc) _mem_copy_gl, &transfer);
419 
420   return (GstMemory *) transfer.dest;
421 }
422 
423 static GstMemory *
_mem_share(GstGLBaseMemory * mem,gssize offset,gssize size)424 _mem_share (GstGLBaseMemory * mem, gssize offset, gssize size)
425 {
426   return NULL;
427 }
428 
429 static gboolean
_mem_is_span(GstGLBaseMemory * mem1,GstGLBaseMemory * mem2,gsize * offset)430 _mem_is_span (GstGLBaseMemory * mem1, GstGLBaseMemory * mem2, gsize * offset)
431 {
432   return FALSE;
433 }
434 
435 static GstMemory *
_mem_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)436 _mem_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params)
437 {
438   g_critical ("Subclass should override GstAllocatorClass::alloc() function");
439 
440   return NULL;
441 }
442 
443 static void
_default_destroy(GstGLBaseMemory * mem)444 _default_destroy (GstGLBaseMemory * mem)
445 {
446 }
447 
448 static void
_destroy_gl_objects(GstGLContext * context,GstGLBaseMemory * mem)449 _destroy_gl_objects (GstGLContext * context, GstGLBaseMemory * mem)
450 {
451   GstGLBaseMemoryAllocatorClass *alloc_class;
452 
453   alloc_class = GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (mem->mem.allocator);
454 
455   g_return_if_fail (alloc_class->destroy != NULL);
456 
457   alloc_class->destroy (mem);
458 
459   if (mem->query)
460     gst_gl_query_free (mem->query);
461 }
462 
463 static void
_mem_free(GstAllocator * allocator,GstMemory * memory)464 _mem_free (GstAllocator * allocator, GstMemory * memory)
465 {
466   GstGLBaseMemory *mem = (GstGLBaseMemory *) memory;
467 
468   GST_CAT_TRACE (GST_CAT_GL_BASE_MEMORY, "freeing buffer memory:%p", mem);
469 
470   gst_gl_context_thread_add (mem->context,
471       (GstGLContextThreadFunc) _destroy_gl_objects, mem);
472 
473   g_mutex_clear (&mem->lock);
474 
475   if (mem->alloc_data) {
476     g_free (mem->alloc_data);
477     mem->alloc_data = NULL;
478   }
479   mem->data = NULL;
480 
481   if (mem->notify)
482     mem->notify (mem->user_data);
483 
484   gst_object_unref (mem->context);
485 
486   g_free (memory);
487 }
488 
489 /**
490  * gst_gl_base_memory_init_once:
491  *
492  * Initializes the GL Base Memory allocator. It is safe to call this function
493  * multiple times.  This must be called before any other GstGLBaseMemory operation.
494  *
495  * Since: 1.8
496  */
497 void
gst_gl_base_memory_init_once(void)498 gst_gl_base_memory_init_once (void)
499 {
500   static volatile gsize _init = 0;
501 
502   if (g_once_init_enter (&_init)) {
503     GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_BASE_MEMORY, "glbasememory", 0,
504         "OpenGL BaseMemory");
505 
506     g_once_init_leave (&_init, 1);
507   }
508 }
509 
510 G_DEFINE_ABSTRACT_TYPE (GstGLBaseMemoryAllocator, gst_gl_base_memory_allocator,
511     GST_TYPE_ALLOCATOR);
512 
513 static void
gst_gl_base_memory_allocator_class_init(GstGLBaseMemoryAllocatorClass * klass)514 gst_gl_base_memory_allocator_class_init (GstGLBaseMemoryAllocatorClass * klass)
515 {
516   GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
517 
518   allocator_class->alloc = _mem_alloc;
519   allocator_class->free = _mem_free;
520 
521   klass->create = _default_create;
522   klass->copy = _default_copy;
523   klass->destroy = _default_destroy;
524 }
525 
526 static void
gst_gl_base_memory_allocator_init(GstGLBaseMemoryAllocator * allocator)527 gst_gl_base_memory_allocator_init (GstGLBaseMemoryAllocator * allocator)
528 {
529   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
530 
531   /* Keep the fallback copy function around, we will need it when copying with
532    * at an offset or smaller size */
533   allocator->fallback_mem_copy = alloc->mem_copy;
534 
535   alloc->mem_map_full = (GstMemoryMapFullFunction) _mem_map_full;
536   alloc->mem_unmap_full = (GstMemoryUnmapFullFunction) _mem_unmap_full;
537   alloc->mem_copy = (GstMemoryCopyFunction) _mem_copy;
538   alloc->mem_share = (GstMemoryShareFunction) _mem_share;
539   alloc->mem_is_span = (GstMemoryIsSpanFunction) _mem_is_span;
540 }
541 
542 /**
543  * gst_is_gl_base_memory:
544  * @mem:a #GstMemory
545  *
546  * Returns: whether the memory at @mem is a #GstGLBaseMemory
547  *
548  * Since: 1.8
549  */
550 gboolean
gst_is_gl_base_memory(GstMemory * mem)551 gst_is_gl_base_memory (GstMemory * mem)
552 {
553   return mem != NULL && mem->allocator != NULL &&
554       g_type_is_a (G_OBJECT_TYPE (mem->allocator),
555       GST_TYPE_GL_BASE_MEMORY_ALLOCATOR);
556 }
557 
558 /**
559  * gst_gl_base_memory_memcpy:
560  * @src: the source #GstGLBaseMemory
561  * @dest: the destination #GstGLBaseMemory
562  * @offset: the offset to start at
563  * @size: the number of bytes to copy
564  *
565  * Returns: whether the copy suceeded.
566  *
567  * Since: 1.8
568  */
569 gboolean
gst_gl_base_memory_memcpy(GstGLBaseMemory * src,GstGLBaseMemory * dest,gssize offset,gssize size)570 gst_gl_base_memory_memcpy (GstGLBaseMemory * src, GstGLBaseMemory * dest,
571     gssize offset, gssize size)
572 {
573   GstMapInfo sinfo, dinfo;
574 
575   if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (dest)))
576     return FALSE;
577 
578   if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ)) {
579     GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY,
580         "could not read map source memory %p", src);
581     return FALSE;
582   }
583 
584   if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE)) {
585     GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY,
586         "could not write map dest memory %p", dest);
587     gst_memory_unmap ((GstMemory *) src, &sinfo);
588     return FALSE;
589   }
590 
591   if (size == -1)
592     size = sinfo.size > offset ? sinfo.size - offset : 0;
593 
594   GST_CAT_DEBUG (GST_CAT_GL_BASE_MEMORY,
595       "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, src, dest);
596   memcpy (dinfo.data, sinfo.data + offset, size);
597   gst_memory_unmap ((GstMemory *) dest, &dinfo);
598   gst_memory_unmap ((GstMemory *) src, &sinfo);
599 
600   return TRUE;
601 }
602 
603 /**
604  * gst_gl_allocation_params_init: (skip)
605  * @params: the #GstGLAllocationParams to initialize
606  * @struct_size: the struct size of the implementation
607  * @alloc_flags: some alloc flags
608  * @copy: a copy function
609  * @free: a free function
610  * @context: (transfer none): a #GstGLContext
611  * @alloc_size: the number of bytes to allocate.
612  * @alloc_params: (transfer none) (allow-none): a #GstAllocationParams to apply
613  * @wrapped_data: (transfer none) (allow-none): a sysmem data pointer to initialize the allocation with
614  * @gl_handle: (transfer none): a GL handle to initialize the allocation with
615  * @user_data: (transfer none) (allow-none): user data to call @notify with
616  * @notify: (allow-none): a #GDestroyNotify
617  *
618  * @notify will be called once for each allocated memory using these @params
619  * when freeing the memory.
620  *
621  * Returns: whether the paramaters could be initialized
622  *
623  * Since: 1.8
624  */
625 gboolean
gst_gl_allocation_params_init(GstGLAllocationParams * params,gsize struct_size,guint alloc_flags,GstGLAllocationParamsCopyFunc copy,GstGLAllocationParamsFreeFunc free,GstGLContext * context,gsize alloc_size,GstAllocationParams * alloc_params,gpointer wrapped_data,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)626 gst_gl_allocation_params_init (GstGLAllocationParams * params,
627     gsize struct_size, guint alloc_flags, GstGLAllocationParamsCopyFunc copy,
628     GstGLAllocationParamsFreeFunc free, GstGLContext * context,
629     gsize alloc_size, GstAllocationParams * alloc_params,
630     gpointer wrapped_data, gpointer gl_handle, gpointer user_data,
631     GDestroyNotify notify)
632 {
633   memset (params, 0, sizeof (*params));
634 
635   g_return_val_if_fail (struct_size > 0, FALSE);
636   g_return_val_if_fail (copy != NULL, FALSE);
637   g_return_val_if_fail (free != NULL, FALSE);
638   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
639 
640   params->struct_size = struct_size;
641   params->alloc_size = alloc_size;
642   params->copy = copy;
643   params->free = free;
644   params->alloc_flags = alloc_flags;
645   params->context = gst_object_ref (context);
646   if (alloc_params)
647     params->alloc_params = gst_allocation_params_copy (alloc_params);
648   params->notify = notify;
649   params->user_data = user_data;
650   params->wrapped_data = wrapped_data;
651   params->gl_handle = gl_handle;
652 
653   return TRUE;
654 }
655 
656 /**
657  * gst_gl_allocation_params_copy:
658  * @src: the #GstGLAllocationParams to initialize
659  *
660  * Returns: (transfer full): a copy of the #GstGLAllocationParams specified by
661  *          @src or %NULL on failure
662  *
663  * Since: 1.8
664  */
665 GstGLAllocationParams *
gst_gl_allocation_params_copy(GstGLAllocationParams * src)666 gst_gl_allocation_params_copy (GstGLAllocationParams * src)
667 {
668   GstGLAllocationParams *dest;
669 
670   g_return_val_if_fail (src != NULL, NULL);
671 
672   dest = g_malloc0 (src->struct_size);
673 
674   if (src->copy)
675     src->copy (src, dest);
676 
677   return dest;
678 }
679 
680 /**
681  * gst_gl_allocation_params_free:
682  * @params: the #GstGLAllocationParams to initialize
683  *
684  * Frees the #GstGLAllocationParams and all associated data.
685  *
686  * Since: 1.8
687  */
688 void
gst_gl_allocation_params_free(GstGLAllocationParams * params)689 gst_gl_allocation_params_free (GstGLAllocationParams * params)
690 {
691   if (params->free)
692     params->free (params);
693 
694   g_free (params);
695 }
696 
697 /**
698  * gst_gl_allocation_params_free_data:
699  * @params: the source #GstGLAllocationParams
700  *
701  * Frees the dynamically allocated data in @params.  Direct subclasses
702  * should call this function in their own overriden free function.
703  *
704  * Since: 1.8
705  */
706 void
gst_gl_allocation_params_free_data(GstGLAllocationParams * params)707 gst_gl_allocation_params_free_data (GstGLAllocationParams * params)
708 {
709   if (params->context)
710     gst_object_unref (params->context);
711   if (params->alloc_params)
712     gst_allocation_params_free (params->alloc_params);
713 }
714 
715 /**
716  * gst_gl_allocation_params_copy_data:
717  * @src: the source #GstGLAllocationParams
718  * @dest: the destination #GstGLAllocationParams
719  *
720  * Copies the dynamically allocated data from @src to @dest.  Direct subclasses
721  * should call this function in their own overriden copy function.
722  *
723  * Since: 1.8
724  */
725 void
gst_gl_allocation_params_copy_data(GstGLAllocationParams * src,GstGLAllocationParams * dest)726 gst_gl_allocation_params_copy_data (GstGLAllocationParams * src,
727     GstGLAllocationParams * dest)
728 {
729   gst_gl_allocation_params_init (dest, src->struct_size, src->alloc_flags,
730       src->copy, src->free, src->context, src->alloc_size, NULL,
731       src->wrapped_data, src->gl_handle, src->user_data, src->notify);
732 
733   if (src->alloc_params)
734     dest->alloc_params = gst_allocation_params_copy (src->alloc_params);
735 }
736 
737 G_DEFINE_BOXED_TYPE (GstGLAllocationParams, gst_gl_allocation_params,
738     (GBoxedCopyFunc) gst_gl_allocation_params_copy,
739     (GBoxedFreeFunc) gst_gl_allocation_params_free);
740 
741 /**
742  * gst_gl_base_memory_alloc:
743  * @allocator: a #GstGLBaseMemoryAllocator
744  * @params: the #GstGLAllocationParams to allocate the memory with
745  *
746  * Returns: a new #GstGLBaseMemory from @allocator with the requested @params.
747  *
748  * Since: 1.8
749  */
750 GstGLBaseMemory *
gst_gl_base_memory_alloc(GstGLBaseMemoryAllocator * allocator,GstGLAllocationParams * params)751 gst_gl_base_memory_alloc (GstGLBaseMemoryAllocator * allocator,
752     GstGLAllocationParams * params)
753 {
754   GstGLBaseMemoryAllocatorClass *alloc_class;
755 
756   g_return_val_if_fail (GST_IS_GL_BASE_MEMORY_ALLOCATOR (allocator), NULL);
757 
758   alloc_class = GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (allocator);
759 
760   g_return_val_if_fail (alloc_class != NULL, NULL);
761   g_return_val_if_fail (alloc_class->alloc != NULL, NULL);
762 
763   return alloc_class->alloc (allocator, params);
764 }
765