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