• 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 "gstglrenderbuffer.h"
28 
29 #include "gstglcontext.h"
30 #include "gstglfuncs.h"
31 #include "gstglmemory.h"
32 
33 /**
34  * SECTION:gstglrenderbuffer
35  * @title: GstGLRenderBuffer
36  * @short_description: memory subclass for GL renderbuffer objects
37  * @see_also: #GstMemory, #GstAllocator
38  *
39  * GstGLRenderbuffer is a #GstGLBaseMemory subclass providing support for
40  * OpenGL renderbuffers.
41  *
42  * #GstGLRenderbuffer is created or wrapped through gst_gl_base_memory_alloc()
43  * with #GstGLRenderbufferAllocationParams.
44  *
45  * Since: 1.10
46  */
47 
48 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
49 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
50 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
51 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
52 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
53 
54 static GstAllocator *_gl_renderbuffer_allocator;
55 
56 GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_RENDERBUFFER);
57 #define GST_CAT_DEFAULT GST_CAT_GL_RENDERBUFFER
58 
59 G_DEFINE_TYPE (GstGLRenderbufferAllocator, gst_gl_renderbuffer_allocator,
60     GST_TYPE_GL_BASE_MEMORY_ALLOCATOR);
61 
62 GST_DEFINE_MINI_OBJECT_TYPE (GstGLRenderbuffer, gst_gl_renderbuffer);
63 
64 static guint
_new_renderbuffer(GstGLContext * context,guint format,guint width,guint height)65 _new_renderbuffer (GstGLContext * context, guint format, guint width,
66     guint height)
67 {
68   const GstGLFuncs *gl = context->gl_vtable;
69   guint rbo_id;
70 
71   gl->GenRenderbuffers (1, &rbo_id);
72   gl->BindRenderbuffer (GL_RENDERBUFFER, rbo_id);
73 
74   gl->RenderbufferStorage (GL_RENDERBUFFER, format, width, height);
75 
76   gl->BindRenderbuffer (GL_RENDERBUFFER, 0);
77 
78   return rbo_id;
79 }
80 
81 static gboolean
_gl_rbo_create(GstGLRenderbuffer * gl_mem,GError ** error)82 _gl_rbo_create (GstGLRenderbuffer * gl_mem, GError ** error)
83 {
84   if (!gl_mem->renderbuffer_wrapped) {
85     GstGLContext *context = gl_mem->mem.context;
86     GLenum internal_format;
87     GLenum tex_format;
88     GLenum renderbuffer_type;
89 
90     tex_format = gl_mem->renderbuffer_format;
91     renderbuffer_type = GL_UNSIGNED_BYTE;
92     if (gl_mem->renderbuffer_format == GST_GL_RGB565) {
93       tex_format = GST_GL_RGB;
94       renderbuffer_type = GL_UNSIGNED_SHORT_5_6_5;
95     }
96 
97     internal_format =
98         gst_gl_sized_gl_format_from_gl_format_type (context, tex_format,
99         renderbuffer_type);
100 
101     gl_mem->renderbuffer_id =
102         _new_renderbuffer (context, internal_format,
103         gst_gl_renderbuffer_get_width (gl_mem),
104         gst_gl_renderbuffer_get_height (gl_mem));
105 
106     GST_CAT_TRACE (GST_CAT_GL_RENDERBUFFER, "Generating renderbuffer id:%u "
107         "format:%u dimensions:%ux%u", gl_mem->renderbuffer_id, internal_format,
108         gst_gl_renderbuffer_get_width (gl_mem),
109         gst_gl_renderbuffer_get_height (gl_mem));
110   }
111 
112   return TRUE;
113 }
114 
115 static void
gst_gl_renderbuffer_init(GstGLRenderbuffer * mem,GstAllocator * allocator,GstMemory * parent,GstGLContext * context,GstGLFormat renderbuffer_format,const GstAllocationParams * params,guint width,guint height,gpointer user_data,GDestroyNotify notify)116 gst_gl_renderbuffer_init (GstGLRenderbuffer * mem, GstAllocator * allocator,
117     GstMemory * parent, GstGLContext * context,
118     GstGLFormat renderbuffer_format, const GstAllocationParams * params,
119     guint width, guint height, gpointer user_data, GDestroyNotify notify)
120 {
121   gsize size;
122   guint tex_type;
123 
124   tex_type = GL_UNSIGNED_BYTE;
125   if (renderbuffer_format == GST_GL_RGB565)
126     tex_type = GL_UNSIGNED_SHORT_5_6_5;
127   size =
128       gst_gl_format_type_n_bytes (renderbuffer_format,
129       tex_type) * width * height;
130 
131   mem->renderbuffer_format = renderbuffer_format;
132   mem->width = width;
133   mem->height = height;
134 
135   gst_gl_base_memory_init ((GstGLBaseMemory *) mem, allocator, parent, context,
136       params, size, user_data, notify);
137 
138   GST_CAT_DEBUG (GST_CAT_GL_RENDERBUFFER, "new GL renderbuffer context:%"
139       GST_PTR_FORMAT " memory:%p format:%u dimensions:%ux%u ", context, mem,
140       mem->renderbuffer_format, gst_gl_renderbuffer_get_width (mem),
141       gst_gl_renderbuffer_get_height (mem));
142 }
143 
144 static gpointer
_gl_rbo_map(GstGLRenderbuffer * gl_mem,GstMapInfo * info,gsize maxsize)145 _gl_rbo_map (GstGLRenderbuffer * gl_mem, GstMapInfo * info, gsize maxsize)
146 {
147   GST_CAT_WARNING (GST_CAT_GL_RENDERBUFFER, "Renderbuffer's cannot be mapped");
148 
149   return NULL;
150 }
151 
152 static void
_gl_rbo_unmap(GstGLRenderbuffer * gl_mem,GstMapInfo * info)153 _gl_rbo_unmap (GstGLRenderbuffer * gl_mem, GstMapInfo * info)
154 {
155 }
156 
157 static GstMemory *
_gl_rbo_copy(GstGLRenderbuffer * src,gssize offset,gssize size)158 _gl_rbo_copy (GstGLRenderbuffer * src, gssize offset, gssize size)
159 {
160   GST_CAT_WARNING (GST_CAT_GL_RENDERBUFFER, "Renderbuffer's cannot be copied");
161 
162   return NULL;
163 }
164 
165 static GstMemory *
_gl_rbo_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)166 _gl_rbo_alloc (GstAllocator * allocator, gsize size,
167     GstAllocationParams * params)
168 {
169   g_warning ("Use gst_gl_base_memory_alloc to allocate from this allocator");
170 
171   return NULL;
172 }
173 
174 static void
_gl_rbo_destroy(GstGLRenderbuffer * gl_mem)175 _gl_rbo_destroy (GstGLRenderbuffer * gl_mem)
176 {
177   const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable;
178 
179   if (gl_mem->renderbuffer_id && !gl_mem->renderbuffer_wrapped)
180     gl->DeleteRenderbuffers (1, &gl_mem->renderbuffer_id);
181 }
182 
183 static GstGLRenderbuffer *
_default_gl_rbo_alloc(GstGLRenderbufferAllocator * allocator,GstGLRenderbufferAllocationParams * params)184 _default_gl_rbo_alloc (GstGLRenderbufferAllocator * allocator,
185     GstGLRenderbufferAllocationParams * params)
186 {
187   guint alloc_flags = params->parent.alloc_flags;
188   GstGLRenderbuffer *mem;
189 
190   g_return_val_if_fail ((alloc_flags &
191           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) == 0, NULL);
192 
193   mem = g_new0 (GstGLRenderbuffer, 1);
194 
195   if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
196     mem->renderbuffer_id = GPOINTER_TO_UINT (params->parent.gl_handle);
197     mem->renderbuffer_wrapped = TRUE;
198   }
199 
200   gst_gl_renderbuffer_init (mem, GST_ALLOCATOR_CAST (allocator), NULL,
201       params->parent.context, params->renderbuffer_format,
202       params->parent.alloc_params, params->width, params->height,
203       params->parent.user_data, params->parent.notify);
204 
205   return mem;
206 }
207 
208 static void
gst_gl_renderbuffer_allocator_class_init(GstGLRenderbufferAllocatorClass * klass)209 gst_gl_renderbuffer_allocator_class_init (GstGLRenderbufferAllocatorClass *
210     klass)
211 {
212   GstGLBaseMemoryAllocatorClass *gl_base;
213   GstAllocatorClass *allocator_class;
214 
215   gl_base = (GstGLBaseMemoryAllocatorClass *) klass;
216   allocator_class = (GstAllocatorClass *) klass;
217 
218   gl_base->alloc =
219       (GstGLBaseMemoryAllocatorAllocFunction) _default_gl_rbo_alloc;
220   gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_rbo_create;
221   gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_rbo_destroy;
222 
223   allocator_class->alloc = _gl_rbo_alloc;
224 }
225 
226 static void
gst_gl_renderbuffer_allocator_init(GstGLRenderbufferAllocator * allocator)227 gst_gl_renderbuffer_allocator_init (GstGLRenderbufferAllocator * allocator)
228 {
229   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
230 
231   alloc->mem_type = GST_GL_RENDERBUFFER_ALLOCATOR_NAME;
232 
233   alloc->mem_map_full = (GstMemoryMapFullFunction) _gl_rbo_map;
234   alloc->mem_unmap_full = (GstMemoryUnmapFullFunction) _gl_rbo_unmap;
235   alloc->mem_copy = (GstMemoryCopyFunction) _gl_rbo_copy;
236 
237   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
238 }
239 
240 /**
241  * gst_gl_renderbuffer_get_width:
242  * @gl_mem: a #GstGLRenderbuffer
243  *
244  * Returns: the configured width of @gl_mem
245  *
246  * Since: 1.10
247  */
248 gint
gst_gl_renderbuffer_get_width(GstGLRenderbuffer * gl_mem)249 gst_gl_renderbuffer_get_width (GstGLRenderbuffer * gl_mem)
250 {
251   g_return_val_if_fail (gst_is_gl_renderbuffer ((GstMemory *) gl_mem), 0);
252 
253   return gl_mem->width;
254 }
255 
256 /**
257  * gst_gl_renderbuffer_get_height:
258  * @gl_mem: a #GstGLRenderbuffer
259  *
260  * Returns: the configured height of @gl_mem
261  *
262  * Since: 1.10
263  */
264 gint
gst_gl_renderbuffer_get_height(GstGLRenderbuffer * gl_mem)265 gst_gl_renderbuffer_get_height (GstGLRenderbuffer * gl_mem)
266 {
267   g_return_val_if_fail (gst_is_gl_renderbuffer ((GstMemory *) gl_mem), 0);
268 
269   return gl_mem->height;
270 }
271 
272 /**
273  * gst_gl_renderbuffer_get_format:
274  * @gl_mem: a #GstGLRenderbuffer
275  *
276  * Returns: the #GstGLFormat of @gl_mem
277  *
278  * Since: 1.12
279  */
280 GstGLFormat
gst_gl_renderbuffer_get_format(GstGLRenderbuffer * gl_mem)281 gst_gl_renderbuffer_get_format (GstGLRenderbuffer * gl_mem)
282 {
283   g_return_val_if_fail (gst_is_gl_renderbuffer ((GstMemory *) gl_mem), 0);
284 
285   return gl_mem->renderbuffer_format;
286 }
287 
288 /**
289  * gst_gl_renderbuffer_get_id:
290  * @gl_mem: a #GstGLRenderbuffer
291  *
292  * Returns: the OpenGL renderbuffer handle of @gl_mem
293  *
294  * Since: 1.10
295  */
296 guint
gst_gl_renderbuffer_get_id(GstGLRenderbuffer * gl_mem)297 gst_gl_renderbuffer_get_id (GstGLRenderbuffer * gl_mem)
298 {
299   g_return_val_if_fail (gst_is_gl_renderbuffer ((GstMemory *) gl_mem), 0);
300 
301   return gl_mem->renderbuffer_id;
302 }
303 
304 /**
305  * gst_gl_renderbuffer_init_once:
306  *
307  * Initializes the GL Base Texture allocator. It is safe to call this function
308  * multiple times.  This must be called before any other GstGLRenderbuffer operation.
309  *
310  * Since: 1.10
311  */
312 void
gst_gl_renderbuffer_init_once(void)313 gst_gl_renderbuffer_init_once (void)
314 {
315   static gsize _init = 0;
316 
317   if (g_once_init_enter (&_init)) {
318     gst_gl_base_memory_init_once ();
319 
320     GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_RENDERBUFFER, "glrenderbuffermemory", 0,
321         "OpenGL Renderbuffer memory");
322 
323     _gl_renderbuffer_allocator =
324         g_object_new (GST_TYPE_GL_RENDERBUFFER_ALLOCATOR, NULL);
325     gst_object_ref_sink (_gl_renderbuffer_allocator);
326     GST_OBJECT_FLAG_SET (_gl_renderbuffer_allocator,
327         GST_OBJECT_FLAG_MAY_BE_LEAKED);
328 
329     gst_allocator_register (GST_GL_RENDERBUFFER_ALLOCATOR_NAME,
330         _gl_renderbuffer_allocator);
331 
332     g_once_init_leave (&_init, 1);
333   }
334 }
335 
336 /**
337  * gst_is_gl_renderbuffer:
338  * @mem:a #GstMemory
339  *
340  * Returns: whether the memory at @mem is a #GstGLRenderbuffer
341  *
342  * Since: 1.10
343  */
344 gboolean
gst_is_gl_renderbuffer(GstMemory * mem)345 gst_is_gl_renderbuffer (GstMemory * mem)
346 {
347   return mem != NULL && mem->allocator != NULL
348       && g_type_is_a (G_OBJECT_TYPE (mem->allocator),
349       GST_TYPE_GL_RENDERBUFFER_ALLOCATOR);
350 }
351 
352 G_DEFINE_BOXED_TYPE (GstGLRenderbufferAllocationParams,
353     gst_gl_renderbuffer_allocation_params,
354     (GBoxedCopyFunc) gst_gl_allocation_params_copy,
355     (GBoxedFreeFunc) gst_gl_allocation_params_free);
356 
357 static void
_gst_gl_rb_alloc_params_free_data(GstGLRenderbufferAllocationParams * params)358 _gst_gl_rb_alloc_params_free_data (GstGLRenderbufferAllocationParams * params)
359 {
360   gst_gl_allocation_params_free_data (&params->parent);
361 }
362 
363 static void
_gst_gl_rb_alloc_params_copy_data(GstGLRenderbufferAllocationParams * src_vid,GstGLRenderbufferAllocationParams * dest_vid)364 _gst_gl_rb_alloc_params_copy_data (GstGLRenderbufferAllocationParams * src_vid,
365     GstGLRenderbufferAllocationParams * dest_vid)
366 {
367   GstGLAllocationParams *src = (GstGLAllocationParams *) src_vid;
368   GstGLAllocationParams *dest = (GstGLAllocationParams *) dest_vid;
369 
370   gst_gl_allocation_params_copy_data (src, dest);
371 
372   dest_vid->renderbuffer_format = src_vid->renderbuffer_format;
373   dest_vid->width = src_vid->width;
374   dest_vid->height = src_vid->height;
375 }
376 
377 static gboolean
_gst_gl_renderbuffer_allocation_params_init_full(GstGLRenderbufferAllocationParams * params,gsize struct_size,guint alloc_flags,GstGLAllocationParamsCopyFunc copy,GstGLAllocationParamsFreeFunc free,GstGLContext * context,const GstAllocationParams * alloc_params,guint width,guint height,GstGLFormat renderbuffer_format,gpointer wrapped_data,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)378     _gst_gl_renderbuffer_allocation_params_init_full
379     (GstGLRenderbufferAllocationParams * params, gsize struct_size,
380     guint alloc_flags, GstGLAllocationParamsCopyFunc copy,
381     GstGLAllocationParamsFreeFunc free, GstGLContext * context,
382     const GstAllocationParams * alloc_params, guint width, guint height,
383     GstGLFormat renderbuffer_format, gpointer wrapped_data,
384     gpointer gl_handle, gpointer user_data, GDestroyNotify notify)
385 {
386   g_return_val_if_fail (params != NULL, FALSE);
387   g_return_val_if_fail (copy != NULL, FALSE);
388   g_return_val_if_fail (free != NULL, FALSE);
389   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
390 
391   memset (params, 0, sizeof (*params));
392 
393   if (!gst_gl_allocation_params_init ((GstGLAllocationParams *) params,
394           struct_size, alloc_flags, copy, free, context, 0, alloc_params,
395           wrapped_data, gl_handle, user_data, notify))
396     return FALSE;
397 
398   params->renderbuffer_format = renderbuffer_format;
399   params->width = width;
400   params->height = height;
401 
402   return TRUE;
403 }
404 
405 /**
406  * gst_gl_renderbuffer_allocation_params_new:
407  * @context: a #GstGLContext
408  * @alloc_params: (allow-none): the #GstAllocationParams for sysmem mappings of the texture
409  * @width: the width of the renderbuffer
410  * @height: the height of the renderbuffer
411  * @renderbuffer_format: the #GstGLFormat for the created textures
412  *
413  * Returns: a new #GstGLRenderbufferAllocationParams for allocating #GstGLRenderbuffer's
414  *
415  * Since: 1.10
416  */
417 GstGLRenderbufferAllocationParams *
gst_gl_renderbuffer_allocation_params_new(GstGLContext * context,const GstAllocationParams * alloc_params,GstGLFormat renderbuffer_format,guint width,guint height)418 gst_gl_renderbuffer_allocation_params_new (GstGLContext * context,
419     const GstAllocationParams * alloc_params, GstGLFormat renderbuffer_format,
420     guint width, guint height)
421 {
422   GstGLRenderbufferAllocationParams *params =
423       g_new0 (GstGLRenderbufferAllocationParams, 1);
424 
425   if (!_gst_gl_renderbuffer_allocation_params_init_full (params,
426           sizeof (GstGLRenderbufferAllocationParams),
427           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_ALLOC |
428           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
429           (GstGLAllocationParamsCopyFunc) _gst_gl_rb_alloc_params_copy_data,
430           (GstGLAllocationParamsFreeFunc) _gst_gl_rb_alloc_params_free_data,
431           context, alloc_params, width, height, renderbuffer_format, NULL, 0,
432           NULL, NULL)) {
433     g_free (params);
434     return NULL;
435   }
436 
437   return params;
438 }
439 
440 /**
441  * gst_gl_renderbuffer_allocation_params_new_wrapped:
442  * @context: a #GstGLContext
443  * @alloc_params: (allow-none): the #GstAllocationParams for @tex_id
444  * @width: the width of the renderbuffer
445  * @height: the height of the renderbuffer
446  * @renderbuffer_format: the #GstGLFormat for @tex_id
447  * @gl_handle: the GL handle to wrap
448  * @user_data: (allow-none): user data to call @notify with
449  * @notify: (allow-none): a #GDestroyNotify
450  *
451  * Returns: a new #GstGLRenderbufferAllocationParams for wrapping @gl_handle as a
452  *          renderbuffer
453  *
454  * Since: 1.10
455  */
456 GstGLRenderbufferAllocationParams *
gst_gl_renderbuffer_allocation_params_new_wrapped(GstGLContext * context,const GstAllocationParams * alloc_params,GstGLFormat renderbuffer_format,guint width,guint height,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)457 gst_gl_renderbuffer_allocation_params_new_wrapped (GstGLContext * context,
458     const GstAllocationParams * alloc_params, GstGLFormat renderbuffer_format,
459     guint width, guint height, gpointer gl_handle, gpointer user_data,
460     GDestroyNotify notify)
461 {
462   GstGLRenderbufferAllocationParams *params =
463       g_new0 (GstGLRenderbufferAllocationParams, 1);
464 
465   if (!_gst_gl_renderbuffer_allocation_params_init_full (params,
466           sizeof (GstGLRenderbufferAllocationParams),
467           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE |
468           GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
469           (GstGLAllocationParamsCopyFunc) _gst_gl_rb_alloc_params_copy_data,
470           (GstGLAllocationParamsFreeFunc) _gst_gl_rb_alloc_params_free_data,
471           context, alloc_params, width, height, renderbuffer_format, NULL,
472           gl_handle, user_data, notify)) {
473     g_free (params);
474     return NULL;
475   }
476 
477   return params;
478 }
479