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