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 "gstglmemory.h"
28
29 #include "gl.h"
30 #include "gstglcontext_private.h"
31 #include "gstglfuncs.h"
32
33 /**
34 * SECTION:gstglmemory
35 * @title: GstGLMemory
36 * @short_description: memory subclass for GL textures
37 * @see_also: #GstMemory, #GstAllocator, #GstGLBufferPool
38 *
39 * GstGLMemory is a #GstGLBaseMemory subclass providing support for the mapping of
40 * OpenGL textures.
41 *
42 * #GstGLMemory is created or wrapped through gst_gl_base_memory_alloc()
43 * with #GstGLVideoAllocationParams.
44 *
45 * Data is uploaded or downloaded from the GPU as is necessary.
46 *
47 * The #GstCaps that is used for #GstGLMemory based buffers should contain
48 * the %GST_CAPS_FEATURE_MEMORY_GL_MEMORY as a #GstCapsFeatures and should
49 * contain a 'texture-target' field with one of the #GstGLTextureTarget values
50 * as a string, i.e. some combination of 'texture-target=(string){2D,
51 * rectangle, external-oes}'.
52 */
53
54 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
55 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
56 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
57 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
58 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
59
60 #define GL_MEM_WIDTH(gl_mem) _get_plane_width (&gl_mem->info, gl_mem->plane)
61 #define GL_MEM_HEIGHT(gl_mem) _get_plane_height (&gl_mem->info, gl_mem->plane)
62 #define GL_MEM_STRIDE(gl_mem) GST_VIDEO_INFO_PLANE_STRIDE (&gl_mem->info, gl_mem->plane)
63
64 static GstAllocator *_gl_memory_allocator;
65
66 GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY);
67 #define GST_CAT_DEFAULT GST_CAT_GL_MEMORY
68
69 /* compatibility definitions... */
70 #ifndef GL_UNPACK_ROW_LENGTH
71 #define GL_UNPACK_ROW_LENGTH 0x0CF2
72 #endif
73
74 #ifndef GL_TEXTURE_RECTANGLE
75 #define GL_TEXTURE_RECTANGLE 0x84F5
76 #endif
77 #ifndef GL_TEXTURE_EXTERNAL_OES
78 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
79 #endif
80
81 #ifndef GL_READ_FRAMEBUFFER
82 #define GL_READ_FRAMEBUFFER 0x8CA8
83 #endif
84 #ifndef GL_DRAW_FRAMEBUFFER
85 #define GL_DRAW_FRAMEBUFFER 0x8CA9
86 #endif
87
88 G_DEFINE_TYPE (GstGLMemoryAllocator, gst_gl_memory_allocator,
89 GST_TYPE_GL_BASE_MEMORY_ALLOCATOR);
90
91 GST_DEFINE_MINI_OBJECT_TYPE (GstGLMemory, gst_gl_memory);
92
93 typedef struct
94 {
95 /* in */
96 GstGLMemory *src;
97 GstGLFormat out_format;
98 guint out_width, out_height;
99 GstGLTextureTarget tex_target;
100 GstGLFormat tex_format;
101 /* inout */
102 guint tex_id;
103 /* out */
104 gboolean result;
105 } GstGLMemoryCopyParams;
106
107 static inline guint
_get_plane_width(const GstVideoInfo * info,guint plane)108 _get_plane_width (const GstVideoInfo * info, guint plane)
109 {
110 if (GST_VIDEO_INFO_IS_YUV (info)) {
111 gint comp[GST_VIDEO_MAX_COMPONENTS];
112 gst_video_format_info_component (info->finfo, plane, comp);
113 return GST_VIDEO_INFO_COMP_WIDTH (info, comp[0]);
114 } else {
115 /* RGB, GRAY */
116 return GST_VIDEO_INFO_WIDTH (info);
117 }
118 }
119
120 static inline guint
_get_plane_height(const GstVideoInfo * info,guint plane)121 _get_plane_height (const GstVideoInfo * info, guint plane)
122 {
123 if (GST_VIDEO_INFO_IS_YUV (info)) {
124 gint comp[GST_VIDEO_MAX_COMPONENTS];
125 gst_video_format_info_component (info->finfo, plane, comp);
126 return GST_VIDEO_INFO_COMP_HEIGHT (info, comp[0]);
127 } else {
128 /* RGB, GRAY */
129 return GST_VIDEO_INFO_HEIGHT (info);
130 }
131 }
132
133 static inline void
_calculate_unpack_length(GstGLMemory * gl_mem,GstGLContext * context)134 _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context)
135 {
136 guint n_gl_bytes;
137 GstGLFormat tex_format;
138 guint tex_type;
139
140 gl_mem->tex_scaling[0] = 1.0f;
141 gl_mem->tex_scaling[1] = 1.0f;
142 gl_mem->unpack_length = 1;
143 gl_mem->tex_width = GL_MEM_WIDTH (gl_mem);
144
145 gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &tex_format,
146 &tex_type);
147 n_gl_bytes = gst_gl_format_type_n_bytes (tex_format, tex_type);
148 if (n_gl_bytes == 0) {
149 GST_ERROR ("Unsupported texture type %d", gl_mem->tex_format);
150 return;
151 }
152
153 if (USING_OPENGL (context) || USING_GLES3 (context)
154 || USING_OPENGL3 (context)) {
155 gl_mem->unpack_length = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
156 } else if (USING_GLES2 (context)) {
157 guint j = 8;
158
159 while (j >= n_gl_bytes) {
160 /* GST_ROUND_UP_j(GL_MEM_WIDTH (gl_mem) * n_gl_bytes) */
161 guint round_up_j =
162 ((GL_MEM_WIDTH (gl_mem) * n_gl_bytes) + j - 1) & ~(j - 1);
163
164 if (round_up_j == GL_MEM_STRIDE (gl_mem)) {
165 GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on "
166 "width (with plane width:%u, plane stride:%u and pixel stride:%u. "
167 "RU%u(%u*%u) = %u)", j, GL_MEM_WIDTH (gl_mem),
168 GL_MEM_STRIDE (gl_mem), n_gl_bytes, j, GL_MEM_WIDTH (gl_mem),
169 n_gl_bytes, round_up_j);
170
171 gl_mem->unpack_length = j;
172 break;
173 }
174 j >>= 1;
175 }
176
177 if (j < n_gl_bytes) {
178 /* Failed to find a suitable alignment, try based on plane_stride and
179 * scale in the shader. Useful for alignments that are greater than 8.
180 */
181 j = 8;
182
183 while (j >= n_gl_bytes) {
184 /* GST_ROUND_UP_j((GL_MEM_STRIDE (gl_mem)) */
185 guint round_up_j = ((GL_MEM_STRIDE (gl_mem)) + j - 1) & ~(j - 1);
186
187 if (round_up_j == (GL_MEM_STRIDE (gl_mem))) {
188 GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based "
189 "on stride (with plane stride:%u and pixel stride:%u. "
190 "RU%u(%u) = %u)", j, GL_MEM_STRIDE (gl_mem), n_gl_bytes, j,
191 GL_MEM_STRIDE (gl_mem), round_up_j);
192
193 gl_mem->unpack_length = j;
194 gl_mem->tex_scaling[0] =
195 (gfloat) (GL_MEM_WIDTH (gl_mem) * n_gl_bytes) /
196 (gfloat) GL_MEM_STRIDE (gl_mem);
197 gl_mem->tex_width = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
198 break;
199 }
200 j >>= 1;
201 }
202
203 if (j < n_gl_bytes) {
204 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to find matching "
205 "alignment. Image may look corrupted. plane width:%u, "
206 "plane stride:%u and pixel stride:%u", GL_MEM_WIDTH (gl_mem),
207 GL_MEM_STRIDE (gl_mem), n_gl_bytes);
208 }
209 }
210 }
211
212 if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_RECTANGLE) {
213 guint w_sub =
214 GST_VIDEO_FORMAT_INFO_W_SUB (gl_mem->info.finfo, gl_mem->plane);
215 guint h_sub =
216 GST_VIDEO_FORMAT_INFO_H_SUB (gl_mem->info.finfo, gl_mem->plane);
217
218 if (w_sub)
219 gl_mem->tex_scaling[0] /= (1 << w_sub);
220 if (h_sub)
221 gl_mem->tex_scaling[1] /= (1 << h_sub);
222 }
223 }
224
225 static guint
_new_texture(GstGLContext * context,guint target,guint internal_format,guint format,guint type,guint width,guint height)226 _new_texture (GstGLContext * context, guint target, guint internal_format,
227 guint format, guint type, guint width, guint height)
228 {
229 const GstGLFuncs *gl = context->gl_vtable;
230 guint tex_id;
231
232 gl->GenTextures (1, &tex_id);
233 gl->BindTexture (target, tex_id);
234 if (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE)
235 gl->TexImage2D (target, 0, internal_format, width, height, 0, format, type,
236 NULL);
237
238 gl->TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
239 gl->TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240 gl->TexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
241 gl->TexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
242
243 gl->BindTexture (target, 0);
244
245 return tex_id;
246 }
247
248 static gboolean
_gl_tex_create(GstGLMemory * gl_mem,GError ** error)249 _gl_tex_create (GstGLMemory * gl_mem, GError ** error)
250 {
251 GstGLContext *context = gl_mem->mem.context;
252 GstGLFormat internal_format;
253 GstGLFormat tex_format;
254 GLenum tex_type;
255
256 internal_format = gl_mem->tex_format;
257 gst_gl_format_type_from_sized_gl_format (internal_format, &tex_format,
258 &tex_type);
259 internal_format =
260 gst_gl_sized_gl_format_from_gl_format_type (context, tex_format,
261 tex_type);
262
263 if (!gl_mem->texture_wrapped) {
264 gl_mem->tex_id =
265 _new_texture (context, gst_gl_texture_target_to_gl (gl_mem->tex_target),
266 internal_format, tex_format, tex_type, gl_mem->tex_width,
267 GL_MEM_HEIGHT (gl_mem));
268
269 GST_TRACE ("Generating texture id:%u format:%u type:%u dimensions:%ux%u",
270 gl_mem->tex_id, tex_format, tex_type, gl_mem->tex_width,
271 GL_MEM_HEIGHT (gl_mem));
272 }
273
274 return TRUE;
275 }
276
277 static void
_gst_gl_memory_start_log(GstGLMemory * gl_mem,const gchar * func_name)278 _gst_gl_memory_start_log (GstGLMemory * gl_mem, const gchar * func_name)
279 {
280 /* debugging is disabled */
281 if (!GST_GL_BASE_MEMORY_CAST (gl_mem)->query)
282 return;
283
284 gst_gl_query_start_log (GST_GL_BASE_MEMORY_CAST (gl_mem)->query,
285 GST_CAT_GL_MEMORY, GST_LEVEL_LOG, NULL, "%s took", func_name);
286 }
287
288 static void
_gst_gl_memory_end_log(GstGLMemory * gl_mem)289 _gst_gl_memory_end_log (GstGLMemory * gl_mem)
290 {
291 /* debugging is disabled */
292 if (!GST_GL_BASE_MEMORY_CAST (gl_mem)->query)
293 return;
294
295 gst_gl_query_end (GST_GL_BASE_MEMORY_CAST (gl_mem)->query);
296 }
297
298 /**
299 * gst_gl_memory_init:
300 * @mem: the #GstGLBaseMemory to initialize
301 * @allocator: the #GstAllocator to initialize with
302 * @parent: (allow-none): the parent #GstMemory to initialize with
303 * @context: the #GstGLContext to initialize with
304 * @target: the #GstGLTextureTarget for this #GstGLMemory
305 * @tex_format: the #GstGLFormat for this #GstGLMemory
306 * @params: (allow-none): the @GstAllocationParams to initialize with
307 * @info: the #GstVideoInfo for this #GstGLMemory
308 * @plane: the plane number (starting from 0) for this #GstGLMemory
309 * @valign: (allow-none): optional #GstVideoAlignment parameters
310 * @notify: (allow-none): a #GDestroyNotify
311 * @user_data: (allow-none): user data to call @notify with
312 *
313 * Initializes @mem with the required parameters. @info is assumed to have
314 * already have been modified with gst_video_info_align().
315 *
316 * Since: 1.8
317 */
318 void
gst_gl_memory_init(GstGLMemory * mem,GstAllocator * allocator,GstMemory * parent,GstGLContext * context,GstGLTextureTarget target,GstGLFormat tex_format,const GstAllocationParams * params,const GstVideoInfo * info,guint plane,const GstVideoAlignment * valign,gpointer user_data,GDestroyNotify notify)319 gst_gl_memory_init (GstGLMemory * mem, GstAllocator * allocator,
320 GstMemory * parent, GstGLContext * context, GstGLTextureTarget target,
321 GstGLFormat tex_format, const GstAllocationParams * params,
322 const GstVideoInfo * info, guint plane, const GstVideoAlignment * valign,
323 gpointer user_data, GDestroyNotify notify)
324 {
325 const gchar *target_str;
326 gsize size;
327
328 g_return_if_fail (plane < GST_VIDEO_INFO_N_PLANES (info));
329
330 mem->info = *info;
331 if (valign)
332 mem->valign = *valign;
333 else
334 gst_video_alignment_reset (&mem->valign);
335
336 /* double-check alignment requirements (caller should've taken care of this) */
337 if (params) {
338 guint max_align, n;
339
340 max_align = gst_memory_alignment;
341 max_align |= params->align;
342 for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
343 max_align |= mem->valign.stride_align[n];
344
345 if (params->align < max_align && max_align > gst_memory_alignment) {
346 GST_WARNING ("allocation params alignment %" G_GSIZE_FORMAT " is smaller "
347 "than the max required video alignment %u", params->align, max_align);
348 }
349 }
350
351 size = gst_gl_get_plane_data_size (info, valign, plane);
352
353 mem->tex_target = target;
354 mem->tex_format = tex_format;
355 mem->plane = plane;
356
357 _calculate_unpack_length (mem, context);
358
359 gst_gl_base_memory_init ((GstGLBaseMemory *) mem, allocator, parent, context,
360 params, size, user_data, notify);
361
362 target_str = gst_gl_texture_target_to_string (target);
363 GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture context:%"
364 GST_PTR_FORMAT " memory:%p target:%s format:%u dimensions:%ux%u "
365 "stride:%u size:%" G_GSIZE_FORMAT, context, mem, target_str,
366 mem->tex_format, mem->tex_width, GL_MEM_HEIGHT (mem), GL_MEM_STRIDE (mem),
367 mem->mem.mem.size);
368 }
369
370 /**
371 * gst_gl_memory_read_pixels:
372 * @gl_mem: a #GstGLMemory
373 * @write_pointer: the data pointer to pass to glReadPixels
374 *
375 * Reads the texture in #GstGLMemory into @write_pointer if no buffer is bound
376 * to `GL_PIXEL_PACK_BUFFER`. Otherwise @write_pointer is the byte offset into
377 * the currently bound `GL_PIXEL_PACK_BUFFER` buffer to store the result of
378 * glReadPixels. See the OpenGL specification for glReadPixels for more
379 * details.
380 *
381 * Returns: whether theread operation succeeded
382 *
383 * Since: 1.8
384 */
385 gboolean
gst_gl_memory_read_pixels(GstGLMemory * gl_mem,gpointer write_pointer)386 gst_gl_memory_read_pixels (GstGLMemory * gl_mem, gpointer write_pointer)
387 {
388 GstGLContext *context = gl_mem->mem.context;
389 const GstGLFuncs *gl = context->gl_vtable;
390 GstGLFormat format;
391 guint type;
392 guint fbo;
393
394 gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &format, &type);
395
396 /* FIXME: avoid creating a framebuffer every download/copy */
397 gl->GenFramebuffers (1, &fbo);
398 gl->BindFramebuffer (GL_FRAMEBUFFER, fbo);
399
400 gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
401 gst_gl_texture_target_to_gl (gl_mem->tex_target), gl_mem->tex_id, 0);
402
403 if (!gst_gl_context_check_framebuffer_status (context, GL_FRAMEBUFFER)) {
404 GST_CAT_WARNING (GST_CAT_GL_MEMORY,
405 "Could not create framebuffer to read pixels for memory %p", gl_mem);
406 gl->DeleteFramebuffers (1, &fbo);
407 return FALSE;
408 }
409
410 if (USING_GLES2 (context) || USING_GLES3 (context)) {
411 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
412 /* explicitly supported */
413 } else {
414 gint supported_format, supported_type;
415
416 gl->GetIntegerv (GL_IMPLEMENTATION_COLOR_READ_FORMAT, &supported_format);
417 gl->GetIntegerv (GL_IMPLEMENTATION_COLOR_READ_TYPE, &supported_type);
418
419 if (supported_format != format || supported_type != type) {
420 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "cannot read pixels with "
421 "unsupported format and type. Supported format 0x%x type 0x%x",
422 supported_format, supported_type);
423 gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
424 gl->DeleteFramebuffers (1, &fbo);
425 return FALSE;
426 }
427 }
428 }
429
430 _gst_gl_memory_start_log (gl_mem, "glReadPixels");
431 gl->ReadPixels (0, 0, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem), format,
432 type, write_pointer);
433 _gst_gl_memory_end_log (gl_mem);
434
435 gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
436 gl->DeleteFramebuffers (1, &fbo);
437
438 return TRUE;
439 }
440
441 static gpointer
_gl_tex_download_get_tex_image(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)442 _gl_tex_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info,
443 gsize size)
444 {
445 GstGLContext *context = gl_mem->mem.context;
446 const GstGLFuncs *gl = context->gl_vtable;
447
448 if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize)
449 return NULL;
450
451 if (USING_GLES2 (context) || USING_GLES3 (context))
452 return NULL;
453
454 /* taken care of by read pixels */
455 if (gl_mem->tex_format != GST_GL_LUMINANCE
456 && gl_mem->tex_format != GST_GL_LUMINANCE_ALPHA)
457 return NULL;
458
459 if (info->flags & GST_MAP_READ
460 && GST_MEMORY_FLAG_IS_SET (gl_mem,
461 GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
462 GstGLFormat format;
463 guint type;
464 guint target;
465
466 GST_CAT_TRACE (GST_CAT_GL_MEMORY, "attempting download of texture %u "
467 "using glGetTexImage", gl_mem->tex_id);
468
469 gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &format,
470 &type);
471
472 target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
473 gl->BindTexture (target, gl_mem->tex_id);
474 _gst_gl_memory_start_log (gl_mem, "glGetTexImage");
475 gl->GetTexImage (target, 0, format, type, gl_mem->mem.data);
476 _gst_gl_memory_end_log (gl_mem);
477 gl->BindTexture (target, 0);
478 }
479
480 return gl_mem->mem.data;
481 }
482
483 static gpointer
_gl_tex_download_read_pixels(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)484 _gl_tex_download_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info,
485 gsize size)
486 {
487 if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize)
488 return NULL;
489
490 if (info->flags & GST_MAP_READ
491 && GST_MEMORY_FLAG_IS_SET (gl_mem,
492 GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
493 GST_CAT_TRACE (GST_CAT_GL_MEMORY,
494 "attempting download of texture %u " "using glReadPixels",
495 gl_mem->tex_id);
496 if (!gst_gl_memory_read_pixels (gl_mem, gl_mem->mem.data))
497 return NULL;
498 }
499
500 return gl_mem->mem.data;
501 }
502
503 static gpointer
_gl_tex_map_cpu_access(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)504 _gl_tex_map_cpu_access (GstGLMemory * gl_mem, GstMapInfo * info, gsize size)
505 {
506 gpointer data = NULL;
507
508 if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (gl_mem)))
509 return NULL;
510
511 if (!data)
512 data = _gl_tex_download_get_tex_image (gl_mem, info, size);
513
514 if (!data)
515 data = _gl_tex_download_read_pixels (gl_mem, info, size);
516
517 return data;
518 }
519
520 static void
_upload_cpu_write(GstGLMemory * gl_mem,GstMapInfo * info,gsize maxsize)521 _upload_cpu_write (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize)
522 {
523 gst_gl_memory_texsubimage (gl_mem, gl_mem->mem.data);
524 }
525
526 /**
527 * gst_gl_memory_texsubimage:
528 * @gl_mem: a #GstGLMemory
529 * @read_pointer: the data pointer to pass to glTexSubImage
530 *
531 * Reads the texture in @read_pointer into @gl_mem.
532 *
533 * See gst_gl_memory_read_pixels() for what @read_pointer signifies.
534 *
535 * Since: 1.8
536 */
537 void
gst_gl_memory_texsubimage(GstGLMemory * gl_mem,gpointer read_pointer)538 gst_gl_memory_texsubimage (GstGLMemory * gl_mem, gpointer read_pointer)
539 {
540 GstGLContext *context = gl_mem->mem.context;
541 const GstGLFuncs *gl;
542 GstGLFormat gl_format;
543 GLenum gl_type, gl_target;
544 gpointer data;
545 gsize plane_start;
546
547 if (!GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD))
548 return;
549
550 gl = context->gl_vtable;
551
552 gst_gl_format_type_from_sized_gl_format (gl_mem->tex_format, &gl_format,
553 &gl_type);
554
555 gl_target = gst_gl_texture_target_to_gl (gl_mem->tex_target);
556
557 if (USING_OPENGL (context) || USING_GLES3 (context)
558 || USING_OPENGL3 (context)) {
559 gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length);
560 } else if (USING_GLES2 (context)) {
561 gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length);
562 }
563
564 GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, %ux%u",
565 gl_mem->tex_id, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem));
566
567 /* find the start of the plane data including padding */
568 plane_start =
569 gst_gl_get_plane_start (&gl_mem->info, &gl_mem->valign,
570 gl_mem->plane) + gl_mem->mem.mem.offset;
571
572 data = (gpointer) ((gintptr) plane_start + (gintptr) read_pointer);
573
574 gl->BindTexture (gl_target, gl_mem->tex_id);
575 _gst_gl_memory_start_log (gl_mem, "glTexSubImage");
576 gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->tex_width,
577 GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, data);
578 _gst_gl_memory_end_log (gl_mem);
579
580 /* Reset to default values */
581 if (USING_OPENGL (context) || USING_GLES3 (context)
582 || USING_OPENGL3 (context)) {
583 gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
584 } else if (USING_GLES2 (context)) {
585 gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
586 }
587
588 gl->BindTexture (gl_target, 0);
589 }
590
591 static gpointer
_default_gl_tex_map(GstGLMemory * gl_mem,GstMapInfo * info,gsize size)592 _default_gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize size)
593 {
594 if ((info->flags & GST_MAP_GL) == GST_MAP_GL) {
595 _upload_cpu_write (gl_mem, info, size);
596 return &gl_mem->tex_id;
597 } else {
598 return _gl_tex_map_cpu_access (gl_mem, info, size);
599 }
600 }
601
602 static gpointer
_gl_tex_map(GstGLMemory * gl_mem,GstMapInfo * info,gsize maxsize)603 _gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize)
604 {
605 GstGLMemoryAllocatorClass *alloc_class;
606 gpointer data;
607
608 alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator);
609
610 if ((info->flags & GST_MAP_GL) == GST_MAP_GL) {
611 if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
612 return &gl_mem->tex_id;
613 } else { /* not GL */
614 if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
615 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot map External OES textures");
616 return NULL;
617 }
618 }
619
620 g_return_val_if_fail (alloc_class->map != NULL, NULL);
621 data = alloc_class->map (GST_GL_BASE_MEMORY_CAST (gl_mem), info, maxsize);
622
623 return data;
624 }
625
626 static void
_default_gl_tex_unmap(GstGLMemory * gl_mem,GstMapInfo * info)627 _default_gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info)
628 {
629 }
630
631 static void
_gl_tex_unmap(GstGLMemory * gl_mem,GstMapInfo * info)632 _gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info)
633 {
634 GstGLMemoryAllocatorClass *alloc_class;
635
636 alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator);
637 g_return_if_fail (alloc_class->unmap != NULL);
638
639 alloc_class->unmap (GST_GL_BASE_MEMORY_CAST (gl_mem), info);
640 }
641
642 /**
643 * gst_gl_memory_copy_teximage:
644 * @src: the source #GstGLMemory
645 * @tex_id: the destination texture id
646 * @out_target: the destination #GstGLTextureTarget
647 * @out_tex_format: the destination #GstGLFormat
648 * @out_width: the destination width
649 * @out_height: the destination height
650 *
651 * Copies the texture in #GstGLMemory into the texture specified by @tex_id,
652 * @out_target, @out_tex_format, @out_width and @out_height.
653 *
654 * Returns: whether the copy succeeded.
655 *
656 * Since: 1.8
657 */
658 gboolean
gst_gl_memory_copy_teximage(GstGLMemory * src,guint tex_id,GstGLTextureTarget out_target,GstGLFormat out_tex_format,gint out_width,gint out_height)659 gst_gl_memory_copy_teximage (GstGLMemory * src, guint tex_id,
660 GstGLTextureTarget out_target, GstGLFormat out_tex_format,
661 gint out_width, gint out_height)
662 {
663 const GstGLFuncs *gl;
664 guint out_tex_target;
665 GstMapInfo sinfo;
666 guint src_tex_id;
667 guint fbo[2];
668 guint n_fbos;
669
670 gl = src->mem.context->gl_vtable;
671 out_tex_target = gst_gl_texture_target_to_gl (out_target);
672
673 if (!gl->GenFramebuffers) {
674 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Framebuffer objects not supported");
675 goto error;
676 }
677
678 if (USING_GLES2 (src->mem.context)
679 && (src->tex_format == GST_GL_LUMINANCE
680 || src->tex_format == GST_GL_LUMINANCE_ALPHA)) {
681 GST_CAT_FIXME (GST_CAT_GL_MEMORY,
682 "Cannot copy Luminance/Luminance Alpha textures in GLES");
683 goto error;
684 }
685
686 if (!gst_memory_map (GST_MEMORY_CAST (src), &sinfo,
687 GST_MAP_READ | GST_MAP_GL)) {
688 GST_CAT_ERROR (GST_CAT_GL_MEMORY,
689 "Failed to map source memory for copying");
690 goto error;
691 }
692
693 src_tex_id = *(guint *) sinfo.data;
694
695 GST_CAT_LOG (GST_CAT_GL_MEMORY, "copying memory %p, tex %u into "
696 "texture %i", src, src_tex_id, tex_id);
697
698 /* FIXME: try and avoid creating and destroying fbo's every copy... */
699 if (!gl->BlitFramebuffer || (!gl->DrawBuffer && !gl->DrawBuffers)
700 || !gl->ReadBuffer) {
701 /* create a framebuffer object */
702 n_fbos = 1;
703 gl->GenFramebuffers (n_fbos, &fbo[0]);
704 gl->BindFramebuffer (GL_FRAMEBUFFER, fbo[0]);
705
706 gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
707 gst_gl_texture_target_to_gl (src->tex_target), src_tex_id, 0);
708
709 if (!gst_gl_context_check_framebuffer_status (src->mem.context,
710 GL_FRAMEBUFFER))
711 goto fbo_error;
712
713 gl->BindTexture (out_tex_target, tex_id);
714 _gst_gl_memory_start_log (src, "CopyTexImage2D");
715 gl->CopyTexImage2D (out_tex_target, 0, out_tex_format, 0, 0, out_width,
716 out_height, 0);
717 _gst_gl_memory_end_log (src);
718
719 gl->BindTexture (out_tex_target, 0);
720 gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
721
722 gl->DeleteFramebuffers (n_fbos, &fbo[0]);
723 } else {
724 GLenum multipleRT[] = {
725 GL_COLOR_ATTACHMENT0,
726 GL_COLOR_ATTACHMENT1,
727 GL_COLOR_ATTACHMENT2
728 };
729
730 /* create a framebuffer object */
731 n_fbos = 2;
732 gl->GenFramebuffers (n_fbos, &fbo[0]);
733
734 gl->BindFramebuffer (GL_READ_FRAMEBUFFER, fbo[0]);
735 gl->FramebufferTexture2D (GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
736 gst_gl_texture_target_to_gl (src->tex_target), src_tex_id, 0);
737
738 if (!gst_gl_context_check_framebuffer_status (src->mem.context,
739 GL_READ_FRAMEBUFFER))
740 goto fbo_error;
741
742 gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, fbo[1]);
743
744 gl->FramebufferTexture2D (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
745 gst_gl_texture_target_to_gl (src->tex_target), tex_id, 0);
746
747 if (!gst_gl_context_check_framebuffer_status (src->mem.context,
748 GL_DRAW_FRAMEBUFFER))
749 goto fbo_error;
750
751 gl->BindTexture (out_tex_target, tex_id);
752 _gst_gl_memory_start_log (src, "BlitFramebuffer");
753 gl->ReadBuffer (GL_COLOR_ATTACHMENT0);
754 if (gl->DrawBuffers)
755 gl->DrawBuffers (1, multipleRT);
756 else
757 gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
758 gl->BlitFramebuffer (0, 0, out_width, out_height,
759 0, 0, out_width, out_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
760 _gst_gl_memory_end_log (src);
761
762 gl->BindTexture (out_tex_target, 0);
763 gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
764 gl->BindFramebuffer (GL_READ_FRAMEBUFFER, 0);
765
766 gl->DeleteFramebuffers (n_fbos, &fbo[0]);
767
768 if (gl->DrawBuffer)
769 gl->DrawBuffer (GL_BACK);
770 }
771
772 gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo);
773
774 return TRUE;
775
776 fbo_error:
777 {
778 gl->BindTexture (out_tex_target, 0);
779 if (!gl->BlitFramebuffer) {
780 gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
781 } else {
782 gl->BindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
783 gl->BindFramebuffer (GL_READ_FRAMEBUFFER, 0);
784 }
785
786 gl->DeleteFramebuffers (n_fbos, &fbo[0]);
787
788 gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo);
789 }
790 error:
791 return FALSE;
792 }
793
794 static void
_gl_tex_copy_thread(GstGLContext * context,gpointer data)795 _gl_tex_copy_thread (GstGLContext * context, gpointer data)
796 {
797 GstGLMemoryCopyParams *copy_params;
798
799 copy_params = (GstGLMemoryCopyParams *) data;
800
801 if (!copy_params->tex_id) {
802 GstGLFormat internal_format, out_gl_format;
803 guint out_gl_type, out_tex_target;
804
805 out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target);
806 internal_format = copy_params->src->tex_format;
807 gst_gl_format_type_from_sized_gl_format (internal_format, &out_gl_format,
808 &out_gl_type);
809 internal_format =
810 gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format,
811 out_gl_type);
812
813 copy_params->tex_id =
814 _new_texture (context, out_tex_target,
815 internal_format, out_gl_format, out_gl_type, copy_params->out_width,
816 copy_params->out_height);
817 }
818
819 copy_params->result = gst_gl_memory_copy_teximage (copy_params->src,
820 copy_params->tex_id, copy_params->tex_target, copy_params->tex_format,
821 copy_params->out_width, copy_params->out_height);
822 }
823
824 static GstMemory *
_default_gl_tex_copy(GstGLMemory * src,gssize offset,gssize size)825 _default_gl_tex_copy (GstGLMemory * src, gssize offset, gssize size)
826 {
827 GstAllocationParams params = { 0, GST_MEMORY_CAST (src)->align, 0, 0 };
828 GstGLBaseMemoryAllocator *base_mem_allocator;
829 GstAllocator *allocator;
830 GstGLMemory *dest = NULL;
831
832 allocator = GST_MEMORY_CAST (src)->allocator;
833 base_mem_allocator = (GstGLBaseMemoryAllocator *) allocator;
834
835 if (src->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
836 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures");
837 return NULL;
838 }
839
840 /* If not doing a full copy, then copy to sysmem, the 2D represention of the
841 * texture would become wrong */
842 if (offset > 0 || size < GST_MEMORY_CAST (src)->size) {
843 return base_mem_allocator->fallback_mem_copy (GST_MEMORY_CAST (src), offset,
844 size);
845 }
846
847 dest = g_new0 (GstGLMemory, 1);
848
849 gst_gl_memory_init (dest, allocator, NULL, src->mem.context, src->tex_target,
850 src->tex_format, ¶ms, &src->info, src->plane, &src->valign, NULL,
851 NULL);
852
853 if (!GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) {
854 GstMapInfo dinfo;
855
856 if (!gst_memory_map (GST_MEMORY_CAST (dest), &dinfo,
857 GST_MAP_WRITE | GST_MAP_GL)) {
858 GST_CAT_WARNING (GST_CAT_GL_MEMORY,
859 "Failed not map destination for writing");
860 gst_memory_unref (GST_MEMORY_CAST (dest));
861 return NULL;
862 }
863
864 if (!gst_gl_memory_copy_into ((GstGLMemory *) src,
865 ((GstGLMemory *) dest)->tex_id, src->tex_target,
866 src->tex_format, src->tex_width, GL_MEM_HEIGHT (src))) {
867 GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
868 gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo);
869 goto memcpy;
870 }
871
872 gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo);
873 } else {
874 memcpy:
875 if (!gst_gl_base_memory_memcpy ((GstGLBaseMemory *) src,
876 (GstGLBaseMemory *) dest, offset, size)) {
877 GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
878 gst_memory_unref (GST_MEMORY_CAST (dest));
879 return NULL;
880 }
881 }
882
883 return (GstMemory *) dest;
884 }
885
886 static GstMemory *
_gl_tex_copy(GstGLMemory * src,gssize offset,gssize size)887 _gl_tex_copy (GstGLMemory * src, gssize offset, gssize size)
888 {
889 GstGLMemoryAllocatorClass *alloc_class;
890
891 alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (src->mem.mem.allocator);
892
893 if (src->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) {
894 GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures");
895 return NULL;
896 }
897
898 g_return_val_if_fail (alloc_class->copy, NULL);
899 return (GstMemory *) alloc_class->copy (GST_GL_BASE_MEMORY_CAST (src), offset,
900 size);
901 }
902
903 static GstMemory *
_gl_tex_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)904 _gl_tex_alloc (GstAllocator * allocator, gsize size,
905 GstAllocationParams * params)
906 {
907 g_warning ("Use gst_gl_base_memory_alloc to allocate from this allocator");
908
909 return NULL;
910 }
911
912 static void
_gl_tex_destroy(GstGLMemory * gl_mem)913 _gl_tex_destroy (GstGLMemory * gl_mem)
914 {
915 const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable;
916
917 if (gl_mem->tex_id && !gl_mem->texture_wrapped)
918 gl->DeleteTextures (1, &gl_mem->tex_id);
919 }
920
921 static GstGLMemory *
_default_gl_tex_alloc(GstGLMemoryAllocator * allocator,GstGLVideoAllocationParams * params)922 _default_gl_tex_alloc (GstGLMemoryAllocator * allocator,
923 GstGLVideoAllocationParams * params)
924 {
925 guint alloc_flags = params->parent.alloc_flags;
926 GstGLMemory *mem;
927
928 g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
929 NULL);
930
931 mem = g_new0 (GstGLMemory, 1);
932
933 if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
934 mem->tex_id = GPOINTER_TO_UINT (params->parent.gl_handle);
935 mem->texture_wrapped = TRUE;
936 }
937
938 gst_gl_memory_init (mem, GST_ALLOCATOR_CAST (allocator), NULL,
939 params->parent.context, params->target, params->tex_format,
940 params->parent.alloc_params, params->v_info, params->plane,
941 params->valign, params->parent.user_data, params->parent.notify);
942
943 if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
944 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
945 }
946 if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) {
947 mem->mem.data = params->parent.wrapped_data;
948 GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
949 }
950
951 return mem;
952 }
953
954 static void
gst_gl_memory_allocator_class_init(GstGLMemoryAllocatorClass * klass)955 gst_gl_memory_allocator_class_init (GstGLMemoryAllocatorClass * klass)
956 {
957 GstGLBaseMemoryAllocatorClass *gl_base;
958 GstAllocatorClass *allocator_class;
959
960 gl_base = (GstGLBaseMemoryAllocatorClass *) klass;
961 allocator_class = (GstAllocatorClass *) klass;
962
963 klass->map = (GstGLBaseMemoryAllocatorMapFunction) _default_gl_tex_map;
964 klass->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _default_gl_tex_unmap;
965 klass->copy = (GstGLBaseMemoryAllocatorCopyFunction) _default_gl_tex_copy;
966
967 gl_base->alloc =
968 (GstGLBaseMemoryAllocatorAllocFunction) _default_gl_tex_alloc;
969 gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_tex_create;
970 gl_base->map = (GstGLBaseMemoryAllocatorMapFunction) _gl_tex_map;
971 gl_base->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _gl_tex_unmap;
972 gl_base->copy = (GstGLBaseMemoryAllocatorCopyFunction) _gl_tex_copy;
973 gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_tex_destroy;
974
975 allocator_class->alloc = _gl_tex_alloc;
976 }
977
978 static void
gst_gl_memory_allocator_init(GstGLMemoryAllocator * allocator)979 gst_gl_memory_allocator_init (GstGLMemoryAllocator * allocator)
980 {
981 GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
982
983 alloc->mem_type = GST_GL_MEMORY_ALLOCATOR_NAME;
984
985 GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
986 }
987
988 /**
989 * gst_gl_memory_copy_into:
990 * @gl_mem:a #GstGLMemory
991 * @tex_id:OpenGL texture id
992 * @target: the #GstGLTextureTarget
993 * @tex_format: the #GstGLFormat
994 * @width: width of @tex_id
995 * @height: height of @tex_id
996 *
997 * Copies @gl_mem into the texture specified by @tex_id. The format of @tex_id
998 * is specified by @tex_format, @width and @height.
999 *
1000 * Returns: Whether the copy succeeded
1001 *
1002 * Since: 1.8
1003 */
1004 gboolean
gst_gl_memory_copy_into(GstGLMemory * gl_mem,guint tex_id,GstGLTextureTarget target,GstGLFormat tex_format,gint width,gint height)1005 gst_gl_memory_copy_into (GstGLMemory * gl_mem, guint tex_id,
1006 GstGLTextureTarget target, GstGLFormat tex_format, gint width, gint height)
1007 {
1008 GstGLMemoryCopyParams copy_params;
1009
1010 copy_params.src = gl_mem;
1011 copy_params.tex_id = tex_id;
1012 copy_params.tex_target = target;
1013 copy_params.tex_format = tex_format;
1014 copy_params.out_width = width;
1015 copy_params.out_height = height;
1016
1017 gst_gl_context_thread_add (gl_mem->mem.context, _gl_tex_copy_thread,
1018 ©_params);
1019
1020 return copy_params.result;
1021 }
1022
1023 /**
1024 * gst_gl_memory_get_texture_width:
1025 * @gl_mem: a #GstGLMemory
1026 *
1027 * Returns: the texture width of @gl_mem
1028 *
1029 * Since: 1.8
1030 */
1031 gint
gst_gl_memory_get_texture_width(GstGLMemory * gl_mem)1032 gst_gl_memory_get_texture_width (GstGLMemory * gl_mem)
1033 {
1034 g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1035
1036 return gl_mem->tex_width;
1037 }
1038
1039 /**
1040 * gst_gl_memory_get_texture_height:
1041 * @gl_mem: a #GstGLMemory
1042 *
1043 * Returns: the texture height of @gl_mem
1044 *
1045 * Since: 1.8
1046 */
1047 gint
gst_gl_memory_get_texture_height(GstGLMemory * gl_mem)1048 gst_gl_memory_get_texture_height (GstGLMemory * gl_mem)
1049 {
1050 g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1051
1052 return _get_plane_height (&gl_mem->info, gl_mem->plane);
1053 }
1054
1055 /**
1056 * gst_gl_memory_get_texture_format:
1057 * @gl_mem: a #GstGLMemory
1058 *
1059 * Returns: the #GstGLFormat of @gl_mem
1060 *
1061 * Since: 1.12
1062 */
1063 GstGLFormat
gst_gl_memory_get_texture_format(GstGLMemory * gl_mem)1064 gst_gl_memory_get_texture_format (GstGLMemory * gl_mem)
1065 {
1066 g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1067
1068 return gl_mem->tex_format;
1069 }
1070
1071 /**
1072 * gst_gl_memory_get_texture_target:
1073 * @gl_mem: a #GstGLMemory
1074 *
1075 * Returns: the #GstGLTextureTarget of @gl_mem
1076 *
1077 * Since: 1.8
1078 */
1079 GstGLTextureTarget
gst_gl_memory_get_texture_target(GstGLMemory * gl_mem)1080 gst_gl_memory_get_texture_target (GstGLMemory * gl_mem)
1081 {
1082 g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1083
1084 return gl_mem->tex_target;
1085 }
1086
1087 /**
1088 * gst_gl_memory_get_texture_id:
1089 * @gl_mem: a #GstGLMemory
1090 *
1091 * Returns: the OpenGL texture handle of @gl_mem
1092 *
1093 * Since: 1.8
1094 */
1095 guint
gst_gl_memory_get_texture_id(GstGLMemory * gl_mem)1096 gst_gl_memory_get_texture_id (GstGLMemory * gl_mem)
1097 {
1098 g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1099
1100 return gl_mem->tex_id;
1101 }
1102
1103 /**
1104 * gst_gl_memory_init_once:
1105 *
1106 * Initializes the GL Base Texture allocator. It is safe to call this function
1107 * multiple times. This must be called before any other GstGLMemory operation.
1108 *
1109 * Since: 1.4
1110 */
1111 void
gst_gl_memory_init_once(void)1112 gst_gl_memory_init_once (void)
1113 {
1114 static gsize _init = 0;
1115
1116 if (g_once_init_enter (&_init)) {
1117 gst_gl_base_memory_init_once ();
1118
1119 GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glbasetexture", 0,
1120 "OpenGL Base Texture Memory");
1121
1122 _gl_memory_allocator = g_object_new (GST_TYPE_GL_MEMORY_ALLOCATOR, NULL);
1123 gst_object_ref_sink (_gl_memory_allocator);
1124
1125 gst_allocator_register (GST_GL_MEMORY_ALLOCATOR_NAME, _gl_memory_allocator);
1126
1127 g_once_init_leave (&_init, 1);
1128 }
1129 }
1130
1131 /**
1132 * gst_is_gl_memory:
1133 * @mem:a #GstMemory
1134 *
1135 * Returns: whether the memory at @mem is a #GstGLMemory
1136 *
1137 * Since: 1.4
1138 */
1139 gboolean
gst_is_gl_memory(GstMemory * mem)1140 gst_is_gl_memory (GstMemory * mem)
1141 {
1142 return mem != NULL && mem->allocator != NULL
1143 && g_type_is_a (G_OBJECT_TYPE (mem->allocator),
1144 GST_TYPE_GL_MEMORY_ALLOCATOR);
1145 }
1146
1147 G_DEFINE_BOXED_TYPE (GstGLVideoAllocationParams, gst_gl_video_allocation_params,
1148 (GBoxedCopyFunc) gst_gl_allocation_params_copy,
1149 (GBoxedFreeFunc) gst_gl_allocation_params_free);
1150
1151 static void
_gst_gl_video_allocation_params_set_video_alignment(GstGLVideoAllocationParams * params,const GstVideoAlignment * valign)1152 _gst_gl_video_allocation_params_set_video_alignment (GstGLVideoAllocationParams
1153 * params, const GstVideoAlignment * valign)
1154 {
1155 g_return_if_fail (params != NULL);
1156
1157 if (!params->valign)
1158 params->valign = g_new0 (GstVideoAlignment, 1);
1159
1160 if (valign) {
1161 *params->valign = *valign;
1162 } else {
1163 gst_video_alignment_reset (params->valign);
1164 }
1165 }
1166
1167 /**
1168 * gst_gl_video_allocation_params_init_full: (skip)
1169 * @params: a #GstGLVideoAllocationParams to initialize
1170 * @struct_size: the size of the struct in @params
1171 * @alloc_flags: some allocation flags
1172 * @copy: a copy function
1173 * @free: a free function
1174 * @context: a #GstGLContext
1175 * @alloc_params: (allow-none): the #GstAllocationParams for @wrapped_data
1176 * @v_info: the #GstVideoInfo for @wrapped_data
1177 * @plane: the video plane @wrapped_data represents
1178 * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @wrapped_data
1179 * @target: the #GstGLTextureTarget
1180 * @tex_format: the #GstGLFormat
1181 * @wrapped_data: (allow-none): the optional data pointer to wrap
1182 * @gl_handle: the optional OpenGL handle to wrap or 0
1183 * @user_data: (allow-none): user data to call @notify with
1184 * @notify: (allow-none): a #GDestroyNotify
1185 *
1186 * Intended for subclass usage
1187 *
1188 * Returns: initializes @params with the parameters specified
1189 *
1190 * Since: 1.8
1191 */
1192 gboolean
gst_gl_video_allocation_params_init_full(GstGLVideoAllocationParams * params,gsize struct_size,guint alloc_flags,GstGLAllocationParamsCopyFunc copy,GstGLAllocationParamsFreeFunc free,GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer wrapped_data,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)1193 gst_gl_video_allocation_params_init_full (GstGLVideoAllocationParams * params,
1194 gsize struct_size, guint alloc_flags, GstGLAllocationParamsCopyFunc copy,
1195 GstGLAllocationParamsFreeFunc free, GstGLContext * context,
1196 const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1197 guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1198 GstGLFormat tex_format, gpointer wrapped_data, gpointer gl_handle,
1199 gpointer user_data, GDestroyNotify notify)
1200 {
1201 guint i;
1202
1203 g_return_val_if_fail (params != NULL, FALSE);
1204 g_return_val_if_fail (copy != NULL, FALSE);
1205 g_return_val_if_fail (free != NULL, FALSE);
1206 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1207 g_return_val_if_fail (v_info != NULL, FALSE);
1208
1209 memset (params, 0, sizeof (*params));
1210
1211 if (!gst_gl_allocation_params_init ((GstGLAllocationParams *) params,
1212 struct_size, alloc_flags, copy, free, context, 0, alloc_params,
1213 wrapped_data, gl_handle, user_data, notify))
1214 return FALSE;
1215
1216 params->v_info = g_new0 (GstVideoInfo, 1);
1217 *params->v_info = *v_info;
1218 for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1219 params->v_info->offset[i] = v_info->offset[i];
1220 params->v_info->stride[i] = v_info->stride[i];
1221 }
1222 _gst_gl_video_allocation_params_set_video_alignment (params, valign);
1223 params->target = target;
1224 params->tex_format = tex_format;
1225 params->plane = plane;
1226
1227 return TRUE;
1228 }
1229
1230 /**
1231 * gst_gl_video_allocation_params_new:
1232 * @context: a #GstGLContext
1233 * @alloc_params: (allow-none): the #GstAllocationParams for sysmem mappings of the texture
1234 * @v_info: the #GstVideoInfo for the texture
1235 * @plane: the video plane of @v_info to allocate
1236 * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of the texture
1237 * @target: the #GstGLTextureTarget for the created textures
1238 * @tex_format: the #GstGLFormat for the created textures
1239 *
1240 * Returns: a new #GstGLVideoAllocationParams for allocating #GstGLMemory's
1241 *
1242 * Since: 1.8
1243 */
1244 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format)1245 gst_gl_video_allocation_params_new (GstGLContext * context,
1246 const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1247 guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1248 GstGLFormat tex_format)
1249 {
1250 GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1251
1252 if (!gst_gl_video_allocation_params_init_full (params,
1253 sizeof (GstGLVideoAllocationParams),
1254 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_ALLOC |
1255 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1256 (GstGLAllocationParamsCopyFunc)
1257 gst_gl_video_allocation_params_copy_data,
1258 (GstGLAllocationParamsFreeFunc)
1259 gst_gl_video_allocation_params_free_data, context, alloc_params,
1260 v_info, plane, valign, target, tex_format, NULL, 0, NULL, NULL)) {
1261 g_free (params);
1262 return NULL;
1263 }
1264
1265 return params;
1266 }
1267
1268 /**
1269 * gst_gl_video_allocation_params_new_wrapped_data:
1270 * @context: a #GstGLContext
1271 * @alloc_params: (allow-none): the #GstAllocationParams for @wrapped_data
1272 * @v_info: the #GstVideoInfo for @wrapped_data
1273 * @plane: the video plane @wrapped_data represents
1274 * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @wrapped_data
1275 * @target: the #GstGLTextureTarget for @wrapped_data
1276 * @tex_format: the #GstGLFormat for @wrapped_data
1277 * @wrapped_data: the data pointer to wrap
1278 * @user_data: (allow-none): user data to call @notify with
1279 * @notify: (allow-none): a #GDestroyNotify
1280 *
1281 * Returns: a new #GstGLVideoAllocationParams for wrapping @wrapped_data
1282 *
1283 * Since: 1.8
1284 */
1285 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_data(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer wrapped_data,gpointer user_data,GDestroyNotify notify)1286 gst_gl_video_allocation_params_new_wrapped_data (GstGLContext * context,
1287 const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1288 guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1289 GstGLFormat tex_format, gpointer wrapped_data, gpointer user_data,
1290 GDestroyNotify notify)
1291 {
1292 GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1293
1294 if (!gst_gl_video_allocation_params_init_full (params,
1295 sizeof (GstGLVideoAllocationParams),
1296 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM |
1297 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1298 (GstGLAllocationParamsCopyFunc)
1299 gst_gl_video_allocation_params_copy_data,
1300 (GstGLAllocationParamsFreeFunc)
1301 gst_gl_video_allocation_params_free_data, context, alloc_params,
1302 v_info, plane, valign, target, tex_format, wrapped_data, 0, user_data,
1303 notify)) {
1304 g_free (params);
1305 return NULL;
1306 }
1307
1308 return params;
1309 }
1310
1311 /**
1312 * gst_gl_video_allocation_params_new_wrapped_gl_handle:
1313 * @context: a #GstGLContext
1314 * @alloc_params: (allow-none): the #GstAllocationParams for @tex_id
1315 * @v_info: the #GstVideoInfo for @tex_id
1316 * @plane: the video plane @tex_id represents
1317 * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @tex_id
1318 * @target: the #GstGLTextureTarget for @tex_id
1319 * @tex_format: the #GstGLFormat for @tex_id
1320 * @gl_handle: the GL handle to wrap
1321 * @user_data: (allow-none): user data to call @notify with
1322 * @notify: (allow-none): a #GDestroyNotify
1323 *
1324 * @gl_handle is defined by the specific OpenGL handle being wrapped
1325 * For #GstGLMemory and #GstGLMemoryPBO it is an OpenGL texture id.
1326 * Other memory types may define it to require a different type of parameter.
1327 *
1328 * Returns: a new #GstGLVideoAllocationParams for wrapping @gl_handle
1329 *
1330 * Since: 1.8
1331 */
1332 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_gl_handle(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,gpointer gl_handle,gpointer user_data,GDestroyNotify notify)1333 gst_gl_video_allocation_params_new_wrapped_gl_handle (GstGLContext * context,
1334 const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1335 guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1336 GstGLFormat tex_format, gpointer gl_handle, gpointer user_data,
1337 GDestroyNotify notify)
1338 {
1339 GstGLVideoAllocationParams *params = g_new0 (GstGLVideoAllocationParams, 1);
1340
1341 if (!gst_gl_video_allocation_params_init_full (params,
1342 sizeof (GstGLVideoAllocationParams),
1343 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE |
1344 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1345 (GstGLAllocationParamsCopyFunc)
1346 gst_gl_video_allocation_params_copy_data,
1347 (GstGLAllocationParamsFreeFunc)
1348 gst_gl_video_allocation_params_free_data, context, alloc_params,
1349 v_info, plane, valign, target, tex_format, NULL, gl_handle, user_data,
1350 notify)) {
1351 g_free (params);
1352 return NULL;
1353 }
1354
1355 return params;
1356 }
1357
1358 /**
1359 * gst_gl_video_allocation_params_new_wrapped_texture:
1360 * @context: a #GstGLContext
1361 * @alloc_params: (allow-none): the #GstAllocationParams for @tex_id
1362 * @v_info: the #GstVideoInfo for @tex_id
1363 * @plane: the video plane @tex_id represents
1364 * @valign: (allow-none): any #GstVideoAlignment applied to symem mappings of @tex_id
1365 * @target: the #GstGLTextureTarget for @tex_id
1366 * @tex_format: the #GstGLFormat for @tex_id
1367 * @tex_id: the GL texture to wrap
1368 * @user_data: (allow-none): user data to call @notify with
1369 * @notify: (allow-none): a #GDestroyNotify
1370 *
1371 * Returns: a new #GstGLVideoAllocationParams for wrapping @tex_id
1372 *
1373 * Since: 1.8
1374 */
1375 GstGLVideoAllocationParams *
gst_gl_video_allocation_params_new_wrapped_texture(GstGLContext * context,const GstAllocationParams * alloc_params,const GstVideoInfo * v_info,guint plane,const GstVideoAlignment * valign,GstGLTextureTarget target,GstGLFormat tex_format,guint tex_id,gpointer user_data,GDestroyNotify notify)1376 gst_gl_video_allocation_params_new_wrapped_texture (GstGLContext * context,
1377 const GstAllocationParams * alloc_params, const GstVideoInfo * v_info,
1378 guint plane, const GstVideoAlignment * valign, GstGLTextureTarget target,
1379 GstGLFormat tex_format, guint tex_id, gpointer user_data,
1380 GDestroyNotify notify)
1381 {
1382 return gst_gl_video_allocation_params_new_wrapped_gl_handle (context,
1383 alloc_params, v_info, plane, valign, target, tex_format,
1384 GUINT_TO_POINTER (tex_id), user_data, notify);
1385 }
1386
1387 /**
1388 * gst_gl_video_allocation_params_free_data:
1389 * @params: a #GstGLVideoAllocationParams
1390 *
1391 * Unset and free any dynamically allocated resources. Intended for subclass
1392 * usage only to chain up at the end of a subclass free function.
1393 *
1394 * Since: 1.8
1395 */
1396 void
gst_gl_video_allocation_params_free_data(GstGLVideoAllocationParams * params)1397 gst_gl_video_allocation_params_free_data (GstGLVideoAllocationParams * params)
1398 {
1399 g_free (params->v_info);
1400 g_free (params->valign);
1401
1402 gst_gl_allocation_params_free_data (¶ms->parent);
1403 }
1404
1405 /**
1406 * gst_gl_video_allocation_params_copy_data:
1407 * @src_vid: source #GstGLVideoAllocationParams to copy from
1408 * @dest_vid: destination #GstGLVideoAllocationParams to copy into
1409 *
1410 * Copy and set any dynamically allocated resources in @dest_vid. Intended
1411 * for subclass usage only to chain up at the end of a subclass copy function.
1412 *
1413 * Since: 1.8
1414 */
1415 void
gst_gl_video_allocation_params_copy_data(GstGLVideoAllocationParams * src_vid,GstGLVideoAllocationParams * dest_vid)1416 gst_gl_video_allocation_params_copy_data (GstGLVideoAllocationParams * src_vid,
1417 GstGLVideoAllocationParams * dest_vid)
1418 {
1419 GstGLAllocationParams *src = (GstGLAllocationParams *) src_vid;
1420 GstGLAllocationParams *dest = (GstGLAllocationParams *) dest_vid;
1421 guint i;
1422
1423 gst_gl_allocation_params_copy_data (src, dest);
1424
1425 dest_vid->v_info = g_new0 (GstVideoInfo, 1);
1426 *dest_vid->v_info = *src_vid->v_info;
1427 for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1428 dest_vid->v_info->offset[i] = src_vid->v_info->offset[i];
1429 dest_vid->v_info->stride[i] = src_vid->v_info->stride[i];
1430 }
1431 _gst_gl_video_allocation_params_set_video_alignment (dest_vid,
1432 src_vid->valign);
1433 dest_vid->target = src_vid->target;
1434 dest_vid->tex_format = src_vid->tex_format;
1435 dest_vid->plane = src_vid->plane;
1436 }
1437
1438 /**
1439 * gst_gl_memory_setup_buffer: (skip)
1440 * @allocator: the @GstGLMemoryAllocator to allocate from
1441 * @buffer: a #GstBuffer to setup
1442 * @params: the #GstGLVideoAllocationParams to allocate with
1443 * @tex_formats: (allow-none) (array length=n_wrapped_pointers):
1444 * a list of #GstGLFormat's to allocate with.
1445 * @wrapped_data: (array length=n_wrapped_pointers) (element-type gpointer):
1446 * a list of wrapped data pointers
1447 * @n_wrapped_pointers: the number of elements in @tex_formats and @wrapped_data
1448 *
1449 * Returns: whether the buffer was correctly setup
1450 *
1451 * Since: 1.8
1452 */
1453 gboolean
gst_gl_memory_setup_buffer(GstGLMemoryAllocator * allocator,GstBuffer * buffer,GstGLVideoAllocationParams * params,GstGLFormat * tex_formats,gpointer * wrapped_data,gsize n_wrapped_pointers)1454 gst_gl_memory_setup_buffer (GstGLMemoryAllocator * allocator,
1455 GstBuffer * buffer, GstGLVideoAllocationParams * params,
1456 GstGLFormat * tex_formats, gpointer * wrapped_data,
1457 gsize n_wrapped_pointers)
1458 {
1459 GstGLBaseMemoryAllocator *base_allocator;
1460 guint n_mem, i, v, views;
1461 guint alloc_flags = params->parent.alloc_flags;
1462
1463 g_return_val_if_fail (params != NULL, FALSE);
1464 g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
1465 FALSE);
1466
1467 base_allocator = GST_GL_BASE_MEMORY_ALLOCATOR (allocator);
1468 n_mem = GST_VIDEO_INFO_N_PLANES (params->v_info);
1469
1470 if (GST_VIDEO_INFO_MULTIVIEW_MODE (params->v_info) ==
1471 GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
1472 views = params->v_info->views;
1473 else
1474 views = 1;
1475
1476 if (n_wrapped_pointers == views)
1477 n_mem = 1;
1478
1479 /* Sanity check for the code below; there should be as many pointers as the
1480 * number of memory we are going to create */
1481 g_return_val_if_fail (!wrapped_data
1482 || n_mem * views == n_wrapped_pointers, FALSE);
1483
1484 for (v = 0; v < views; v++) {
1485 GstVideoMeta *meta;
1486
1487 for (i = 0; i < n_mem; i++) {
1488 GstGLMemory *gl_mem;
1489
1490 if (tex_formats) {
1491 params->tex_format = tex_formats[i];
1492 } else {
1493 params->tex_format =
1494 gst_gl_format_from_video_info (params->parent.context,
1495 params->v_info, i);
1496 }
1497
1498 params->plane = i;
1499 if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) {
1500 g_return_val_if_fail (wrapped_data != NULL, FALSE);
1501 params->parent.wrapped_data = wrapped_data[i];
1502 } else if (alloc_flags &
1503 GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
1504 g_return_val_if_fail (wrapped_data != NULL, FALSE);
1505 params->parent.gl_handle = wrapped_data[i];
1506 }
1507
1508 if (!(gl_mem = (GstGLMemory *) gst_gl_base_memory_alloc (base_allocator,
1509 (GstGLAllocationParams *) params)))
1510 return FALSE;
1511
1512 gst_buffer_append_memory (buffer, (GstMemory *) gl_mem);
1513 }
1514
1515 meta = gst_buffer_add_video_meta_full (buffer, v,
1516 GST_VIDEO_INFO_FORMAT (params->v_info),
1517 GST_VIDEO_INFO_WIDTH (params->v_info),
1518 GST_VIDEO_INFO_HEIGHT (params->v_info), n_mem, params->v_info->offset,
1519 params->v_info->stride);
1520
1521 if (params->valign)
1522 gst_video_meta_set_alignment (meta, *params->valign);
1523 }
1524
1525 return TRUE;
1526 }
1527
1528 /**
1529 * gst_gl_memory_allocator_get_default:
1530 * @context: a #GstGLContext
1531 *
1532 * Returns: (transfer full): the default #GstGLMemoryAllocator supported by
1533 * @context
1534 *
1535 * Since: 1.8
1536 */
1537 GstGLMemoryAllocator *
gst_gl_memory_allocator_get_default(GstGLContext * context)1538 gst_gl_memory_allocator_get_default (GstGLContext * context)
1539 {
1540 GstGLMemoryAllocator *allocator = NULL;
1541
1542 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1543
1544 /* we can only use the pbo allocator with GL > 3.0 contexts */
1545 if (gst_gl_context_check_gl_version (context,
1546 GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2, 3, 0)) {
1547 allocator = (GstGLMemoryAllocator *)
1548 gst_allocator_find (GST_GL_MEMORY_PBO_ALLOCATOR_NAME);
1549 } else {
1550 allocator = (GstGLMemoryAllocator *)
1551 gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME);
1552 }
1553
1554 return allocator;
1555 }
1556