gl: initial support for texture targets other than GL_TEXTURE_2D
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / gstglmemory.c
1 /*
2  * GStreamer
3  * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.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 <gst/video/video.h>
28
29 #include "gstglmemory.h"
30 #include "gstglutils.h"
31
32 /**
33  * SECTION:gstglmemory
34  * @short_description: memory subclass for GL textures
35  * @see_also: #GstMemory, #GstAllocator, #GstGLBufferPool
36  *
37  * GstGLMemory is a #GstMemory subclass providing support for the mapping of
38  * GL textures.  
39  *
40  * #GstGLMemory is created through gst_gl_memory_alloc() or system memory can
41  * be wrapped through gst_gl_memory_wrapped().
42  *
43  * Data is uploaded or downloaded from the GPU as is necessary.
44  */
45
46 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
47 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
48 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
49 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
50 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
51
52 #define GL_MEM_WIDTH(gl_mem) _get_plane_width (&gl_mem->info, gl_mem->plane)
53 #define GL_MEM_HEIGHT(gl_mem) _get_plane_height (&gl_mem->info, gl_mem->plane)
54 #define GL_MEM_STRIDE(gl_mem) GST_VIDEO_INFO_PLANE_STRIDE (&gl_mem->info, gl_mem->plane)
55
56 #define CONTEXT_SUPPORTS_PBO_UPLOAD(context) \
57     (gst_gl_context_check_gl_version (context, \
58         GST_GL_API_OPENGL | GST_GL_API_OPENGL3, 2, 1) \
59         || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
60 #define CONTEXT_SUPPORTS_PBO_DOWNLOAD(context) \
61     (gst_gl_context_check_gl_version (context, \
62         GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2, 3, 0))
63
64 GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY);
65 #define GST_CAT_DEFUALT GST_CAT_GL_MEMORY
66
67 static GstAllocator *_gl_allocator;
68
69 /* compatability definitions... */
70 #ifndef GL_RED
71 #define GL_RED 0x1903
72 #endif
73 #ifndef GL_RG
74 #define GL_RG 0x8227
75 #endif
76 #ifndef GL_R8
77 #define GL_R8 0x8229
78 #endif
79 #ifndef GL_RG8
80 #define GL_RG8 0x822B
81 #endif
82 #ifndef GL_PIXEL_PACK_BUFFER
83 #define GL_PIXEL_PACK_BUFFER 0x88EB
84 #endif
85 #ifndef GL_PIXEL_UNPACK_BUFFER
86 #define GL_PIXEL_UNPACK_BUFFER 0x88EC
87 #endif
88 #ifndef GL_STREAM_READ
89 #define GL_STREAM_READ 0x88E1
90 #endif
91 #ifndef GL_STREAM_DRAW
92 #define GL_STREAM_DRAW 0x88E0
93 #endif
94 #ifndef GL_STREAM_COPY
95 #define GL_STREAM_COPY 0x88E2
96 #endif
97 #ifndef GL_UNPACK_ROW_LENGTH
98 #define GL_UNPACK_ROW_LENGTH 0x0CF2
99 #endif
100 #ifndef GL_MAP_READ_BIT
101 #define GL_MAP_READ_BIT 0x0001
102 #endif
103 #ifndef GL_MAP_WRITE_BIT
104 #define GL_MAP_WRITE_BIT 0x0002
105 #endif
106
107 typedef struct
108 {
109   /* in */
110   GstGLMemory *src;
111   GstVideoGLTextureType out_format;
112   guint out_width, out_height;
113   guint out_stride;
114   gboolean respecify;
115   guint tex_target;
116   /* inout */
117   guint tex_id;
118   /* out */
119   gboolean result;
120 } GstGLMemoryCopyParams;
121
122 static inline guint
123 _gl_format_n_components (guint format)
124 {
125   switch (format) {
126     case GST_VIDEO_GL_TEXTURE_TYPE_RGBA:
127     case GL_RGBA:
128       return 4;
129     case GST_VIDEO_GL_TEXTURE_TYPE_RGB:
130     case GST_VIDEO_GL_TEXTURE_TYPE_RGB16:
131     case GL_RGB:
132       return 3;
133     case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA:
134     case GST_VIDEO_GL_TEXTURE_TYPE_RG:
135     case GL_LUMINANCE_ALPHA:
136     case GL_RG:
137       return 2;
138     case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE:
139     case GST_VIDEO_GL_TEXTURE_TYPE_R:
140     case GL_LUMINANCE:
141     case GL_RED:
142       return 1;
143     default:
144       return 0;
145   }
146 }
147
148 static inline guint
149 _gl_type_n_components (guint type)
150 {
151   switch (type) {
152     case GL_UNSIGNED_BYTE:
153       return 1;
154     case GL_UNSIGNED_SHORT_5_6_5:
155       return 3;
156     default:
157       g_assert_not_reached ();
158       return 0;
159   }
160 }
161
162 static inline guint
163 _gl_type_n_bytes (guint type)
164 {
165   switch (type) {
166     case GL_UNSIGNED_BYTE:
167       return 1;
168     case GL_UNSIGNED_SHORT_5_6_5:
169       return 2;
170     default:
171       g_assert_not_reached ();
172       return 0;
173   }
174 }
175
176 static inline guint
177 _gl_format_type_n_bytes (guint format, guint type)
178 {
179   return _gl_format_n_components (format) / _gl_type_n_components (type) *
180       _gl_type_n_bytes (type);
181 }
182
183 static inline GLenum
184 _gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format)
185 {
186   switch (tex_format) {
187     case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA:
188       return GL_LUMINANCE_ALPHA;
189     case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE:
190       return GL_LUMINANCE;
191     case GST_VIDEO_GL_TEXTURE_TYPE_RGBA:
192       return GL_RGBA;
193     case GST_VIDEO_GL_TEXTURE_TYPE_RGB:
194     case GST_VIDEO_GL_TEXTURE_TYPE_RGB16:
195       return GL_RGB;
196     case GST_VIDEO_GL_TEXTURE_TYPE_RG:
197       return GL_RG;
198     case GST_VIDEO_GL_TEXTURE_TYPE_R:
199       return GL_RED;
200     default:
201       return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
202   }
203 }
204
205 static inline guint
206 _gl_texture_type_n_bytes (GstVideoGLTextureType tex_format)
207 {
208   guint format, type;
209
210   format = _gst_gl_format_from_gl_texture_type (tex_format);
211   type = GL_UNSIGNED_BYTE;
212   if (tex_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
213     type = GL_UNSIGNED_SHORT_5_6_5;
214
215   return _gl_format_type_n_bytes (format, type);
216 }
217
218 GstVideoGLTextureType
219 gst_gl_texture_type_from_format (GstGLContext * context,
220     GstVideoFormat v_format, guint plane)
221 {
222 #if GST_GL_HAVE_PLATFORM_EAGL
223   gboolean texture_rg = FALSE;
224 #else
225   gboolean texture_rg =
226       gst_gl_context_check_feature (context, "GL_EXT_texture_rg")
227       || gst_gl_context_check_feature (context, "GL_ARB_texture_rg");
228 #endif
229   guint n_plane_components;
230
231   switch (v_format) {
232     case GST_VIDEO_FORMAT_RGBx:
233     case GST_VIDEO_FORMAT_BGRx:
234     case GST_VIDEO_FORMAT_xRGB:
235     case GST_VIDEO_FORMAT_xBGR:
236     case GST_VIDEO_FORMAT_RGBA:
237     case GST_VIDEO_FORMAT_BGRA:
238     case GST_VIDEO_FORMAT_ARGB:
239     case GST_VIDEO_FORMAT_ABGR:
240     case GST_VIDEO_FORMAT_AYUV:
241       n_plane_components = 4;
242       break;
243     case GST_VIDEO_FORMAT_RGB:
244     case GST_VIDEO_FORMAT_BGR:
245       n_plane_components = 3;
246       break;
247     case GST_VIDEO_FORMAT_RGB16:
248     case GST_VIDEO_FORMAT_BGR16:
249       return GST_VIDEO_GL_TEXTURE_TYPE_RGB16;
250     case GST_VIDEO_FORMAT_GRAY16_BE:
251     case GST_VIDEO_FORMAT_GRAY16_LE:
252     case GST_VIDEO_FORMAT_YUY2:
253     case GST_VIDEO_FORMAT_UYVY:
254       n_plane_components = 2;
255       break;
256     case GST_VIDEO_FORMAT_NV12:
257     case GST_VIDEO_FORMAT_NV21:
258       n_plane_components = plane == 0 ? 1 : 2;
259       break;
260     case GST_VIDEO_FORMAT_GRAY8:
261     case GST_VIDEO_FORMAT_Y444:
262     case GST_VIDEO_FORMAT_Y42B:
263     case GST_VIDEO_FORMAT_Y41B:
264     case GST_VIDEO_FORMAT_I420:
265     case GST_VIDEO_FORMAT_YV12:
266       n_plane_components = 1;
267       break;
268     default:
269       n_plane_components = 4;
270       g_assert_not_reached ();
271       break;
272   }
273
274   switch (n_plane_components) {
275     case 4:
276       return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
277       break;
278     case 3:
279       return GST_VIDEO_GL_TEXTURE_TYPE_RGB;
280       break;
281     case 2:
282       return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_RG :
283           GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
284       break;
285     case 1:
286       return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_R :
287           GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
288       break;
289     default:
290       g_assert_not_reached ();
291       break;
292   }
293
294   return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
295 }
296
297 static inline GLenum
298 _sized_gl_format_from_gl_format_type (GLenum format, GLenum type)
299 {
300   switch (format) {
301     case GL_RGBA:
302       switch (type) {
303         case GL_UNSIGNED_BYTE:
304           return GL_RGBA8;
305           break;
306       }
307       break;
308     case GL_RGB:
309       switch (type) {
310         case GL_UNSIGNED_BYTE:
311           return GL_RGB8;
312           break;
313         case GL_UNSIGNED_SHORT_5_6_5:
314           return GL_RGB;
315           break;
316       }
317       break;
318     case GL_RG:
319       switch (type) {
320         case GL_UNSIGNED_BYTE:
321           return GL_RG8;
322           break;
323       }
324       break;
325     case GL_RED:
326       switch (type) {
327         case GL_UNSIGNED_BYTE:
328           return GL_R8;
329           break;
330       }
331       break;
332     case GL_LUMINANCE:
333       return GL_LUMINANCE;
334       break;
335     case GL_LUMINANCE_ALPHA:
336       return GL_LUMINANCE_ALPHA;
337       break;
338     case GL_ALPHA:
339       return GL_ALPHA;
340       break;
341     default:
342       break;
343   }
344
345   g_assert_not_reached ();
346   return 0;
347 }
348
349 static inline guint
350 _get_plane_width (GstVideoInfo * info, guint plane)
351 {
352   if (GST_VIDEO_INFO_IS_YUV (info))
353     /* For now component width and plane width are the same and the
354      * plane-component mapping matches
355      */
356     return GST_VIDEO_INFO_COMP_WIDTH (info, plane);
357   else                          /* RGB, GRAY */
358     return GST_VIDEO_INFO_WIDTH (info);
359 }
360
361 static inline guint
362 _get_plane_height (GstVideoInfo * info, guint plane)
363 {
364   if (GST_VIDEO_INFO_IS_YUV (info))
365     /* For now component width and plane width are the same and the
366      * plane-component mapping matches
367      */
368     return GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
369   else                          /* RGB, GRAY */
370     return GST_VIDEO_INFO_HEIGHT (info);
371 }
372
373 typedef struct _GenTexture
374 {
375   guint width, height;
376   GLenum gl_target;
377   GLenum gl_format;
378   GLenum gl_type;
379   guint result;
380 } GenTexture;
381
382 static void
383 _generate_texture (GstGLContext * context, GenTexture * data)
384 {
385   const GstGLFuncs *gl = context->gl_vtable;
386   GLenum internal_format;
387
388   GST_CAT_TRACE (GST_CAT_GL_MEMORY,
389       "Generating texture format:%u type:%u dimensions:%ux%u", data->gl_format,
390       data->gl_type, data->width, data->height);
391
392   internal_format =
393       _sized_gl_format_from_gl_format_type (data->gl_format, data->gl_type);
394
395   gl->GenTextures (1, &data->result);
396   gl->BindTexture (data->gl_target, data->result);
397   gl->TexImage2D (data->gl_target, 0, internal_format, data->width,
398       data->height, 0, data->gl_format, data->gl_type, NULL);
399
400   gl->TexParameteri (data->gl_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
401   gl->TexParameteri (data->gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
402   gl->TexParameteri (data->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
403   gl->TexParameteri (data->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
404
405   GST_CAT_LOG (GST_CAT_GL_MEMORY, "generated texture id:%d", data->result);
406 }
407
408 /* find the difference between the start of the plane and where the video
409  * data starts in the plane */
410 static gsize
411 _find_plane_frame_start (GstGLMemory * gl_mem)
412 {
413   gsize plane_start;
414   gint i;
415
416   /* find the start of the plane data including padding */
417   plane_start = 0;
418   for (i = 0; i < gl_mem->plane; i++) {
419     plane_start +=
420         gst_gl_get_plane_data_size (&gl_mem->info, &gl_mem->valign, i);
421   }
422
423   /* offset between the plane data start and where the video frame starts */
424   return (GST_VIDEO_INFO_PLANE_OFFSET (&gl_mem->info,
425           gl_mem->plane)) - plane_start;
426 }
427
428 static void
429 _upload_memory (GstGLContext * context, GstGLMemory * gl_mem)
430 {
431   const GstGLFuncs *gl;
432   GLenum gl_format, gl_type, gl_target;
433   gpointer data;
434   gsize plane_start;
435
436   if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
437     return;
438   }
439
440   gl = context->gl_vtable;
441
442   gl_type = GL_UNSIGNED_BYTE;
443   if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
444     gl_type = GL_UNSIGNED_SHORT_5_6_5;
445
446   gl_format = _gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
447   gl_target = gl_mem->tex_target;
448
449   if (USING_OPENGL (context) || USING_GLES3 (context)
450       || USING_OPENGL3 (context)) {
451     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length);
452   } else if (USING_GLES2 (context)) {
453     gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length);
454   }
455
456   GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, with pbo %u %ux%u",
457       gl_mem->tex_id, gl_mem->transfer_pbo, gl_mem->tex_width,
458       GL_MEM_HEIGHT (gl_mem));
459
460   /* find the start of the plane data including padding */
461   plane_start = _find_plane_frame_start (gl_mem);
462
463   if (gl_mem->transfer_pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (context)) {
464     gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, gl_mem->transfer_pbo);
465     data = (void *) plane_start;
466   } else {
467     data = (gpointer) ((gintptr) plane_start + (gintptr) gl_mem->data);
468   }
469
470   gl->BindTexture (gl_target, gl_mem->tex_id);
471   gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->tex_width,
472       GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, data);
473
474   if (gl_mem->transfer_pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (context))
475     gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
476
477   /* Reset to default values */
478   if (USING_OPENGL (context) || USING_GLES3 (context)) {
479     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
480   } else if (USING_GLES2 (context)) {
481     gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
482   }
483
484   gl->BindTexture (gl_target, 0);
485
486   GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
487 }
488
489 static void
490 _transfer_upload (GstGLContext * context, GstGLMemory * gl_mem)
491 {
492   const GstGLFuncs *gl;
493   gsize size;
494
495   if (!CONTEXT_SUPPORTS_PBO_UPLOAD (context))
496     /* not supported */
497     return;
498
499   gl = context->gl_vtable;
500
501   if (!gl_mem->transfer_pbo)
502     gl->GenBuffers (1, &gl_mem->transfer_pbo);
503
504   GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "uploading texture %u using pbo %u",
505       gl_mem->tex_id, gl_mem->transfer_pbo);
506
507   size = ((GstMemory *) gl_mem)->maxsize;
508
509   if (USING_OPENGL (context) || USING_GLES3 (context)
510       || USING_OPENGL3 (context)) {
511     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length);
512   } else if (USING_GLES2 (context)) {
513     gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length);
514   }
515
516   gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, gl_mem->transfer_pbo);
517   gl->BufferData (GL_PIXEL_UNPACK_BUFFER, size, gl_mem->data, GL_STREAM_DRAW);
518   gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
519
520   /* Reset to default values */
521   if (USING_OPENGL (context) || USING_GLES3 (context)) {
522     gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
523   } else if (USING_GLES2 (context)) {
524     gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
525   }
526 }
527
528 static inline void
529 _calculate_unpack_length (GstGLMemory * gl_mem)
530 {
531   guint n_gl_bytes;
532
533   gl_mem->tex_scaling[0] = 1.0f;
534   gl_mem->tex_scaling[1] = 1.0f;
535   gl_mem->unpack_length = 1;
536   gl_mem->tex_width = GL_MEM_WIDTH (gl_mem);
537
538   n_gl_bytes = _gl_texture_type_n_bytes (gl_mem->tex_type);
539   if (n_gl_bytes == 0) {
540     GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Unsupported texture type %d",
541         gl_mem->tex_type);
542     return;
543   }
544
545   if (USING_OPENGL (gl_mem->context) || USING_GLES3 (gl_mem->context)
546       || USING_OPENGL3 (gl_mem->context)) {
547     gl_mem->unpack_length = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
548   } else if (USING_GLES2 (gl_mem->context)) {
549     guint j = 8;
550
551     while (j >= n_gl_bytes) {
552       /* GST_ROUND_UP_j(GL_MEM_WIDTH (gl_mem) * n_gl_bytes) */
553       guint round_up_j =
554           ((GL_MEM_WIDTH (gl_mem) * n_gl_bytes) + j - 1) & ~(j - 1);
555
556       if (round_up_j == GL_MEM_STRIDE (gl_mem)) {
557         GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on width "
558             "(with plane width:%u, plane stride:%u and pixel stride:%u. "
559             "RU%u(%u*%u) = %u)", j, GL_MEM_WIDTH (gl_mem),
560             GL_MEM_STRIDE (gl_mem), n_gl_bytes, j, GL_MEM_WIDTH (gl_mem),
561             n_gl_bytes, round_up_j);
562
563         gl_mem->unpack_length = j;
564         break;
565       }
566       j >>= 1;
567     }
568
569     if (j < n_gl_bytes) {
570       /* Failed to find a suitable alignment, try based on plane_stride and
571        * scale in the shader.  Useful for alignments that are greater than 8.
572        */
573       j = 8;
574
575       while (j >= n_gl_bytes) {
576         /* GST_ROUND_UP_j((GL_MEM_STRIDE (gl_mem)) */
577         guint round_up_j = ((GL_MEM_STRIDE (gl_mem)) + j - 1) & ~(j - 1);
578
579         if (round_up_j == (GL_MEM_STRIDE (gl_mem))) {
580           GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on "
581               "stride (with plane stride:%u and pixel stride:%u. "
582               "RU%u(%u) = %u)", j, GL_MEM_STRIDE (gl_mem), n_gl_bytes, j,
583               GL_MEM_STRIDE (gl_mem), round_up_j);
584
585           gl_mem->unpack_length = j;
586           gl_mem->tex_scaling[0] =
587               (gfloat) (GL_MEM_WIDTH (gl_mem) * n_gl_bytes) /
588               (gfloat) GL_MEM_STRIDE (gl_mem);
589           gl_mem->tex_width = GL_MEM_STRIDE (gl_mem) / n_gl_bytes;
590           break;
591         }
592         j >>= 1;
593       }
594
595       if (j < n_gl_bytes) {
596         GST_CAT_ERROR
597             (GST_CAT_GL_MEMORY, "Failed to find matching alignment. Image may "
598             "look corrupted. plane width:%u, plane stride:%u and pixel "
599             "stride:%u", GL_MEM_WIDTH (gl_mem), GL_MEM_STRIDE (gl_mem),
600             n_gl_bytes);
601       }
602     }
603   }
604 }
605
606 static void
607 _transfer_download (GstGLContext * context, GstGLMemory * gl_mem)
608 {
609   const GstGLFuncs *gl;
610   gsize plane_start;
611   gsize size;
612   guint format, type;
613   guint fboId;
614
615   if (!CONTEXT_SUPPORTS_PBO_DOWNLOAD (context)
616       || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
617       || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA)
618     /* not supported */
619     return;
620
621   gl = context->gl_vtable;
622
623   if (!gl_mem->transfer_pbo)
624     gl->GenBuffers (1, &gl_mem->transfer_pbo);
625
626   GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "downloading texture %u using pbo %u",
627       gl_mem->tex_id, gl_mem->transfer_pbo);
628
629   size = ((GstMemory *) gl_mem)->maxsize;
630   plane_start = _find_plane_frame_start (gl_mem);
631   format = _gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
632   type = GL_UNSIGNED_BYTE;
633   if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
634     type = GL_UNSIGNED_SHORT_5_6_5;
635
636   gl->BindBuffer (GL_PIXEL_PACK_BUFFER, gl_mem->transfer_pbo);
637   gl->BufferData (GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_READ);
638
639   /* FIXME: try and avoid creating and destroying fbo's every download... */
640   /* create a framebuffer object */
641   gl->GenFramebuffers (1, &fboId);
642   gl->BindFramebuffer (GL_FRAMEBUFFER, fboId);
643
644   gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
645       GL_TEXTURE_2D, gl_mem->tex_id, 0);
646
647   if (!gst_gl_context_check_framebuffer_status (context)) {
648     GST_CAT_ERROR (GST_CAT_GL_MEMORY, "failed to download texture");
649     goto fbo_error;
650   }
651
652   gl->ReadPixels (0, 0, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem), format,
653       type, (void *) plane_start);
654
655 fbo_error:
656   gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
657   gl->DeleteFramebuffers (1, &fboId);
658
659   gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
660 }
661
662 static void
663 _download_memory (GstGLContext * context, GstGLMemory * gl_mem)
664 {
665   const GstGLFuncs *gl;
666   guint format, type;
667   GLuint fboId;
668
669   gl = context->gl_vtable;
670   format = _gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
671   type = GL_UNSIGNED_BYTE;
672   if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
673     type = GL_UNSIGNED_SHORT_5_6_5;
674
675   if (!gl->GenFramebuffers) {
676     gst_gl_context_set_error (context, "Cannot download GL texture "
677         "without support for Framebuffers");
678     goto error;
679   }
680
681   if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2
682       && (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
683           || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA)) {
684     gst_gl_context_set_error (context, "Cannot download GL luminance/"
685         "luminance alpha textures");
686     goto error;
687   }
688
689   GST_CAT_LOG (GST_CAT_GL_MEMORY, "downloading memory %p, tex %u into %p",
690       gl_mem, gl_mem->tex_id, gl_mem->data);
691
692   if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
693       || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA) {
694     gl->BindTexture (gl_mem->tex_target, gl_mem->tex_id);
695     gl->GetTexImage (gl_mem->tex_target, 0, format, type, gl_mem->data);
696     gl->BindTexture (gl_mem->tex_target, 0);
697   } else if (gl_mem->transfer_pbo && CONTEXT_SUPPORTS_PBO_DOWNLOAD (context)) {
698     gsize size = ((GstMemory *) gl_mem)->maxsize;
699     gpointer map_data = NULL;
700
701     gl->BindBuffer (GL_PIXEL_PACK_BUFFER, gl_mem->transfer_pbo);
702     map_data =
703         gl->MapBufferRange (GL_PIXEL_PACK_BUFFER, 0, size, GL_MAP_READ_BIT);
704     if (!map_data) {
705       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "error mapping buffer for download");
706       gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
707       goto read_pixels;
708     }
709
710     /* FIXME: COPY! use glMapBuffer + glSync everywhere to remove this */
711     memcpy (gl_mem->data, map_data, size);
712
713     gl->UnmapBuffer (GL_PIXEL_PACK_BUFFER);
714     gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
715   } else {
716   read_pixels:
717     /* FIXME: try and avoid creating and destroying fbo's every download... */
718     /* create a framebuffer object */
719     gl->GenFramebuffers (1, &fboId);
720     gl->BindFramebuffer (GL_FRAMEBUFFER, fboId);
721
722     gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
723         gl_mem->tex_target, gl_mem->tex_id, 0);
724
725     if (!gst_gl_context_check_framebuffer_status (context))
726       goto fbo_error;
727
728     gl->ReadPixels (0, 0, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem), format,
729         type, gl_mem->data);
730
731     gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
732
733   fbo_error:
734     gl->DeleteFramebuffers (1, &fboId);
735   }
736
737 error:
738   return;
739 }
740
741 static void
742 _gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
743     GstGLContext * context, GstVideoInfo * info, GstVideoAlignment * valign,
744     guint plane, gpointer user_data, GDestroyNotify notify)
745 {
746   gsize maxsize;
747
748   g_return_if_fail (plane < GST_VIDEO_INFO_N_PLANES (info));
749
750   mem->info = *info;
751   if (valign)
752     mem->valign = *valign;
753   else
754     gst_video_alignment_reset (&mem->valign);
755
756   maxsize = gst_gl_get_plane_data_size (info, valign, plane);
757
758   gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE,
759       allocator, parent, maxsize, 0, 0, maxsize);
760
761   mem->context = gst_object_ref (context);
762   mem->tex_type =
763       gst_gl_texture_type_from_format (context, GST_VIDEO_INFO_FORMAT (info),
764       plane);
765   /* we always operate on 2D textures unless we're dealing with wrapped textures */
766   mem->tex_target = GL_TEXTURE_2D;
767   mem->plane = plane;
768   mem->notify = notify;
769   mem->user_data = user_data;
770   mem->data_wrapped = FALSE;
771   mem->texture_wrapped = FALSE;
772
773   g_mutex_init (&mem->lock);
774
775   _calculate_unpack_length (mem);
776
777   GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture memory:%p format:%u "
778       "dimensions:%ux%u stride:%u size:%" G_GSIZE_FORMAT, mem, mem->tex_type,
779       mem->tex_width, GL_MEM_HEIGHT (mem), GL_MEM_STRIDE (mem), maxsize);
780 }
781
782 static GstGLMemory *
783 _gl_mem_new (GstAllocator * allocator, GstMemory * parent,
784     GstGLContext * context, GstVideoInfo * info, GstVideoAlignment * valign,
785     guint plane, gpointer user_data, GDestroyNotify notify)
786 {
787   GstGLMemory *mem;
788   GenTexture data = { 0, };
789   mem = g_slice_new0 (GstGLMemory);
790   _gl_mem_init (mem, allocator, parent, context, info, valign, plane,
791       user_data, notify);
792
793   data.width = mem->tex_width;
794   data.height = GL_MEM_HEIGHT (mem);
795   data.gl_format = _gst_gl_format_from_gl_texture_type (mem->tex_type);
796   data.gl_type = GL_UNSIGNED_BYTE;
797   data.gl_target = mem->tex_target;
798   if (mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
799     data.gl_type = GL_UNSIGNED_SHORT_5_6_5;
800
801   gst_gl_context_thread_add (context,
802       (GstGLContextThreadFunc) _generate_texture, &data);
803   if (!data.result) {
804     GST_CAT_WARNING (GST_CAT_GL_MEMORY,
805         "Could not create GL texture with context:%p", context);
806   }
807
808   GST_CAT_TRACE (GST_CAT_GL_MEMORY, "created texture %u", data.result);
809
810   mem->tex_id = data.result;
811   mem->tex_target = data.gl_target;
812
813   return mem;
814 }
815
816 static gpointer
817 _gl_mem_map (GstGLMemory * gl_mem, gsize maxsize, GstMapFlags flags)
818 {
819   gpointer data;
820
821   g_return_val_if_fail (maxsize == gl_mem->mem.maxsize, NULL);
822
823   g_mutex_lock (&gl_mem->lock);
824
825   if ((flags & GST_MAP_GL) == GST_MAP_GL) {
826     if ((flags & GST_MAP_READ) == GST_MAP_READ) {
827       GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for reading",
828           gl_mem->tex_id);
829       if (GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
830         gst_gl_context_thread_add (gl_mem->context,
831             (GstGLContextThreadFunc) _upload_memory, gl_mem);
832         GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
833       }
834     }
835
836     if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE) {
837       GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for writing",
838           gl_mem->tex_id);
839       GST_GL_MEMORY_FLAG_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
840       GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
841     }
842
843     data = &gl_mem->tex_id;
844   } else {                      /* not GL */
845     if ((flags & GST_MAP_READ) == GST_MAP_READ) {
846       GST_CAT_TRACE (GST_CAT_GL_MEMORY,
847           "mapping GL texture:%u for reading from system memory",
848           gl_mem->tex_id);
849       if (GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD)) {
850         gst_gl_context_thread_add (gl_mem->context,
851             (GstGLContextThreadFunc) _download_memory, gl_mem);
852         GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
853       }
854     }
855
856     if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE) {
857       GST_CAT_TRACE (GST_CAT_GL_MEMORY,
858           "mapping GL texture:%u for writing to system memory", gl_mem->tex_id);
859       GST_GL_MEMORY_FLAG_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
860       GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
861     }
862
863     data = gl_mem->data;
864   }
865
866   gl_mem->map_flags = flags;
867
868   g_mutex_unlock (&gl_mem->lock);
869
870   return data;
871 }
872
873 void
874 gst_gl_memory_download_transfer (GstGLMemory * gl_mem)
875 {
876   g_mutex_lock (&gl_mem->lock);
877
878   gst_gl_context_thread_add (gl_mem->context,
879       (GstGLContextThreadFunc) _transfer_download, gl_mem);
880
881   g_mutex_unlock (&gl_mem->lock);
882 }
883
884 static void
885 _gl_mem_unmap (GstGLMemory * gl_mem)
886 {
887   g_mutex_lock (&gl_mem->lock);
888
889   if (gl_mem->map_flags & GST_MAP_WRITE) {
890     if (!(gl_mem->map_flags & GST_MAP_GL))
891       gst_gl_context_thread_add (gl_mem->context,
892           (GstGLContextThreadFunc) _transfer_upload, gl_mem);
893   }
894
895   gl_mem->map_flags = 0;
896
897   g_mutex_unlock (&gl_mem->lock);
898 }
899
900 static void
901 _gl_mem_copy_thread (GstGLContext * context, gpointer data)
902 {
903   const GstGLFuncs *gl;
904   GstGLMemoryCopyParams *copy_params;
905   GstGLMemory *src;
906   guint tex_id;
907   GLuint out_tex_target;
908   GLuint fboId;
909   gsize out_width, out_height, out_stride;
910   GLuint out_gl_format, out_gl_type;
911   GLuint in_gl_format, in_gl_type;
912   gsize in_size, out_size;
913
914   copy_params = (GstGLMemoryCopyParams *) data;
915   src = copy_params->src;
916   tex_id = copy_params->tex_id;
917   out_tex_target = copy_params->tex_target;
918   out_width = copy_params->out_width;
919   out_height = copy_params->out_height;
920   out_stride = copy_params->out_stride;
921
922   gl = src->context->gl_vtable;
923   out_gl_format = _gst_gl_format_from_gl_texture_type (copy_params->out_format);
924   out_gl_type = GL_UNSIGNED_BYTE;
925   if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
926     out_gl_type = GL_UNSIGNED_SHORT_5_6_5;
927   in_gl_format = _gst_gl_format_from_gl_texture_type (src->tex_type);
928   in_gl_type = GL_UNSIGNED_BYTE;
929   if (src->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
930     in_gl_type = GL_UNSIGNED_SHORT_5_6_5;
931
932   if (!gl->GenFramebuffers) {
933     gst_gl_context_set_error (src->context,
934         "Context, EXT_framebuffer_object not supported");
935     goto error;
936   }
937
938   in_size = GL_MEM_HEIGHT (src) * GL_MEM_STRIDE (src);
939   out_size = out_height * out_stride;
940
941   if (copy_params->respecify) {
942     if (in_size != out_size) {
943       GST_ERROR ("Cannot copy between textures with backing data of different"
944           "sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size,
945           out_size);
946       goto error;
947     }
948   }
949
950   if (!tex_id) {
951     GenTexture data = { 0, };
952     data.width = copy_params->out_width;
953     data.height = copy_params->out_height;
954     data.gl_target = out_tex_target;
955     data.gl_format = out_gl_format;
956     data.gl_type = GL_UNSIGNED_BYTE;
957     if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
958       data.gl_type = GL_UNSIGNED_SHORT_5_6_5;
959
960     _generate_texture (context, &data);
961     tex_id = data.result;
962   }
963
964   if (!tex_id) {
965     GST_CAT_WARNING (GST_CAT_GL_MEMORY,
966         "Could not create GL texture with context:%p", src->context);
967   }
968
969   GST_CAT_LOG (GST_CAT_GL_MEMORY, "copying memory %p, tex %u into texture %i",
970       src, src->tex_id, tex_id);
971
972   /* FIXME: try and avoid creating and destroying fbo's every copy... */
973   /* create a framebuffer object */
974   gl->GenFramebuffers (1, &fboId);
975   gl->BindFramebuffer (GL_FRAMEBUFFER, fboId);
976
977   gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
978       src->tex_target, src->tex_id, 0);
979
980 //  if (!gst_gl_context_check_framebuffer_status (src->context))
981 //    goto fbo_error;
982
983   gl->BindTexture (out_tex_target, tex_id);
984   if (copy_params->respecify) {
985     if (!gl->GenBuffers) {
986       gst_gl_context_set_error (context, "Cannot reinterpret texture contents "
987           "without buffer objects");
988       gl->BindTexture (out_tex_target, 0);
989       goto fbo_error;
990     }
991
992     if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2
993         && (in_gl_format != GL_RGBA || in_gl_type != GL_UNSIGNED_BYTE)) {
994       gst_gl_context_set_error (context, "Cannot copy non RGBA/UNSIGNED_BYTE "
995           "textures on GLES2");
996       gl->BindTexture (out_tex_target, 0);
997       goto fbo_error;
998     }
999
1000     if (!src->pbo)
1001       gl->GenBuffers (1, &src->pbo);
1002
1003     GST_TRACE ("copying texture data with size of %u*%u*%u",
1004         _gl_format_type_n_bytes (in_gl_format, in_gl_type), src->tex_width,
1005         GL_MEM_HEIGHT (src));
1006
1007     /* copy tex */
1008     gl->BindBuffer (GL_PIXEL_PACK_BUFFER, src->pbo);
1009     gl->BufferData (GL_PIXEL_PACK_BUFFER, in_size, NULL, GL_STREAM_COPY);
1010     gl->ReadPixels (0, 0, src->tex_width, GL_MEM_HEIGHT (src), in_gl_format,
1011         in_gl_type, 0);
1012     gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
1013
1014     gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, src->pbo);
1015     gl->TexSubImage2D (out_tex_target, 0, 0, 0, out_width, out_height,
1016         out_gl_format, out_gl_type, 0);
1017
1018     gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
1019   } else {                      /* different sizes */
1020     gl->CopyTexImage2D (out_tex_target, 0, out_gl_format, 0, 0, out_width,
1021         out_height, 0);
1022   }
1023
1024   gl->BindTexture (out_tex_target, 0);
1025   gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
1026
1027   gl->DeleteFramebuffers (1, &fboId);
1028
1029   copy_params->tex_id = tex_id;
1030   copy_params->result = TRUE;
1031
1032   return;
1033
1034 /* ERRORS */
1035 fbo_error:
1036   {
1037     gl->DeleteFramebuffers (1, &fboId);
1038
1039     copy_params->tex_id = 0;
1040     copy_params->result = FALSE;
1041     return;
1042   }
1043
1044 error:
1045   {
1046     copy_params->result = FALSE;
1047     return;
1048   }
1049 }
1050
1051 static GstMemory *
1052 _gl_mem_copy (GstGLMemory * src, gssize offset, gssize size)
1053 {
1054   GstGLMemory *dest;
1055
1056   g_mutex_lock (&((GstGLMemory *) src)->lock);
1057
1058   if (GST_GL_MEMORY_FLAG_IS_SET (src, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
1059     dest = _gl_mem_new (src->mem.allocator, NULL, src->context, &src->info,
1060         &src->valign, src->plane, NULL, NULL);
1061     dest->data = g_try_malloc (src->mem.maxsize);
1062     if (dest->data == NULL) {
1063       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
1064       gst_memory_unref ((GstMemory *) dest);
1065       return NULL;
1066     }
1067     memcpy (dest->data, src->data, src->mem.maxsize);
1068     GST_GL_MEMORY_FLAG_SET (dest, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
1069   } else {
1070     GstGLMemoryCopyParams copy_params;
1071
1072     copy_params.src = src;
1073     copy_params.tex_id = 0;
1074     copy_params.out_format = src->tex_type;
1075     copy_params.out_width = src->tex_width;
1076     copy_params.out_height = GL_MEM_HEIGHT (src);
1077     copy_params.out_stride = GL_MEM_STRIDE (src);
1078     copy_params.respecify = FALSE;
1079
1080     gst_gl_context_thread_add (src->context, _gl_mem_copy_thread, &copy_params);
1081
1082     dest = g_slice_new0 (GstGLMemory);
1083     _gl_mem_init (dest, src->mem.allocator, NULL, src->context, &src->info,
1084         &src->valign, src->plane, NULL, NULL);
1085
1086     if (!copy_params.result) {
1087       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
1088       gst_memory_unref ((GstMemory *) dest);
1089       return NULL;
1090     }
1091
1092     dest->tex_id = copy_params.tex_id;
1093     dest->data = g_try_malloc (src->mem.maxsize);
1094     if (dest->data == NULL) {
1095       GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
1096       gst_memory_unref ((GstMemory *) dest);
1097       return NULL;
1098     }
1099     GST_GL_MEMORY_FLAG_SET (dest, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
1100   }
1101
1102   g_mutex_unlock (&((GstGLMemory *) src)->lock);
1103
1104   return (GstMemory *) dest;
1105 }
1106
1107 static GstMemory *
1108 _gl_mem_share (GstGLMemory * mem, gssize offset, gssize size)
1109 {
1110   return NULL;
1111 }
1112
1113 static gboolean
1114 _gl_mem_is_span (GstGLMemory * mem1, GstGLMemory * mem2, gsize * offset)
1115 {
1116   return FALSE;
1117 }
1118
1119 static GstMemory *
1120 _gl_mem_alloc (GstAllocator * allocator, gsize size,
1121     GstAllocationParams * params)
1122 {
1123   g_warning ("use gst_gl_memory_alloc () to allocate from this "
1124       "GstGLMemory allocator");
1125
1126   return NULL;
1127 }
1128
1129 static void
1130 _destroy_gl_objects (GstGLContext * context, GstGLMemory * gl_mem)
1131 {
1132   const GstGLFuncs *gl = context->gl_vtable;
1133
1134   if (gl_mem->tex_id && !gl_mem->texture_wrapped)
1135     gl->DeleteTextures (1, &gl_mem->tex_id);
1136
1137   if (gl_mem->pbo)
1138     gl->DeleteBuffers (1, &gl_mem->pbo);
1139 }
1140
1141 static void
1142 _gl_mem_free (GstAllocator * allocator, GstMemory * mem)
1143 {
1144   GstGLMemory *gl_mem = (GstGLMemory *) mem;
1145
1146   GST_CAT_TRACE (GST_CAT_GL_MEMORY, "freeing texture %u", gl_mem->tex_id);
1147
1148   gst_gl_context_thread_add (gl_mem->context,
1149       (GstGLContextThreadFunc) _destroy_gl_objects, gl_mem);
1150
1151   if (gl_mem->notify)
1152     gl_mem->notify (gl_mem->user_data);
1153
1154   if (gl_mem->data && !gl_mem->data_wrapped) {
1155     g_free (gl_mem->data);
1156     gl_mem->data = NULL;
1157   }
1158
1159   g_mutex_clear (&gl_mem->lock);
1160
1161   gst_object_unref (gl_mem->context);
1162   g_slice_free (GstGLMemory, gl_mem);
1163 }
1164
1165 /**
1166  * gst_gl_memory_copy_into_texture:
1167  * @gl_mem:a #GstGLMemory
1168  * @tex_id:OpenGL texture id
1169  * @tex_type: a #GstVideoGLTextureType
1170  * @width: width of @tex_id
1171  * @height: height of @tex_id
1172  * @stride: stride of the backing texture data
1173  * @respecify: whether to copy the data or copy per texel
1174  *
1175  * Copies @gl_mem into the texture specfified by @tex_id.  The format of @tex_id
1176  * is specified by @tex_type, @width and @height.
1177  *
1178  * If @respecify is %TRUE, then the copy is performed in terms of the texture
1179  * data.  This is useful for splitting RGBA textures into RG or R textures or
1180  * vice versa. The requirement for this to succeed is that the backing texture
1181  * data must be the same size, i.e. say a RGBA8 texture is converted into a RG8
1182  * texture, then the RG texture must have twice as many pixels available for
1183  * output as the RGBA texture.
1184  *
1185  * Otherwise, if @respecify is %FALSE, then the copy is performed per texel
1186  * using glCopyTexImage.  See the OpenGL specification for details on the
1187  * mappings between texture formats.
1188  *
1189  * Returns: Whether the copy suceeded
1190  */
1191 gboolean
1192 gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id,
1193     GstVideoGLTextureType tex_type, gint width, gint height, gint stride,
1194     gboolean respecify)
1195 {
1196   GstGLMemoryCopyParams copy_params;
1197
1198   copy_params.src = gl_mem;
1199   copy_params.tex_id = tex_id;
1200   copy_params.out_format = tex_type;
1201   copy_params.out_width = width;
1202   copy_params.out_height = height;
1203   copy_params.out_stride = stride;
1204   copy_params.respecify = respecify;
1205
1206   gst_gl_context_thread_add (gl_mem->context, _gl_mem_copy_thread,
1207       &copy_params);
1208
1209   return copy_params.result;
1210 }
1211
1212 /**
1213  * gst_gl_memory_wrapped_texture:
1214  * @context: a #GstGLContext
1215  * @texture_id: the GL texture handle
1216  * @texture_target: the GL texture target
1217  * @info: the #GstVideoInfo of the memory
1218  * @plane: The plane this memory will represent
1219  * @user_data: user data
1220  * @notify: Destroy callback for the user data
1221  *
1222  * Wraps a texture handle into a #GstGLMemory.
1223  *
1224  * Returns: a newly allocated #GstGLMemory
1225  */
1226 GstGLMemory *
1227 gst_gl_memory_wrapped_texture (GstGLContext * context,
1228     guint texture_id, guint texture_target,
1229     GstVideoInfo * info, guint plane, GstVideoAlignment * valign,
1230     gpointer user_data, GDestroyNotify notify)
1231 {
1232   GstGLMemory *mem;
1233
1234   mem = g_slice_new0 (GstGLMemory);
1235   _gl_mem_init (mem, _gl_allocator, NULL, context, info, valign, plane, NULL,
1236       NULL);
1237
1238   mem->tex_id = texture_id;
1239   mem->tex_target = texture_target;
1240   mem->texture_wrapped = TRUE;
1241   mem->data = g_try_malloc (mem->mem.maxsize);
1242   if (mem->data == NULL) {
1243     gst_memory_unref ((GstMemory *) mem);
1244     return NULL;
1245   }
1246
1247   GST_GL_MEMORY_FLAG_SET (mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
1248
1249   return mem;
1250 }
1251
1252 /**
1253  * gst_gl_memory_alloc:
1254  * @context:a #GstGLContext
1255  * @info: the #GstVideoInfo of the memory
1256  * @plane: the plane this memory will represent
1257  * @valign: the #GstVideoAlignment applied to @info
1258  *
1259  * Allocated a new #GstGlMemory.
1260  *
1261  * Returns: a #GstMemory object with a GL texture specified by @vinfo
1262  *          from @context
1263  */
1264 GstMemory *
1265 gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info,
1266     guint plane, GstVideoAlignment * valign)
1267 {
1268   GstGLMemory *mem;
1269
1270   mem = _gl_mem_new (_gl_allocator, NULL, context, info, valign, plane, NULL,
1271       NULL);
1272
1273   mem->data = g_try_malloc (mem->mem.maxsize);
1274   if (mem->data == NULL) {
1275     gst_memory_unref ((GstMemory *) mem);
1276     return NULL;
1277   }
1278
1279   return (GstMemory *) mem;
1280 }
1281
1282 /**
1283  * gst_gl_memory_wrapped:
1284  * @context:a #GstGLContext
1285  * @info: the #GstVideoInfo of the memory and data
1286  * @plane: the plane this memory will represent
1287  * @valign: the #GstVideoAlignment applied to @info
1288  * @data: the data to wrap
1289  * @user_data: data called with for @notify
1290  * @notify: function called with @user_data when @data needs to be freed
1291  * 
1292  * Wrapped @data into a #GstGLMemory. This version will account for padding
1293  * added to the allocation and expressed through @valign.
1294  *
1295  * Returns: a #GstGLMemory object with a GL texture specified by @v_info
1296  *          from @context and contents specified by @data
1297  */
1298 GstGLMemory *
1299 gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * info,
1300     guint plane, GstVideoAlignment * valign, gpointer data, gpointer user_data,
1301     GDestroyNotify notify)
1302 {
1303   GstGLMemory *mem;
1304
1305   mem = _gl_mem_new (_gl_allocator, NULL, context, info, valign, plane,
1306       user_data, notify);
1307
1308   mem->data = data;
1309   mem->data_wrapped = TRUE;
1310
1311   GST_GL_MEMORY_FLAG_SET (mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
1312
1313   return mem;
1314 }
1315
1316 gint
1317 gst_gl_memory_get_texture_width (GstGLMemory * gl_mem)
1318 {
1319   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1320
1321   return gl_mem->tex_width;
1322 }
1323
1324 gint
1325 gst_gl_memory_get_texture_height (GstGLMemory * gl_mem)
1326 {
1327   g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0);
1328
1329   return _get_plane_height (&gl_mem->info, gl_mem->plane);
1330 }
1331
1332 G_DEFINE_TYPE (GstGLAllocator, gst_gl_allocator, GST_TYPE_ALLOCATOR);
1333
1334 static void
1335 gst_gl_allocator_class_init (GstGLAllocatorClass * klass)
1336 {
1337   GstAllocatorClass *allocator_class;
1338
1339   allocator_class = (GstAllocatorClass *) klass;
1340
1341   allocator_class->alloc = _gl_mem_alloc;
1342   allocator_class->free = _gl_mem_free;
1343 }
1344
1345 static void
1346 gst_gl_allocator_init (GstGLAllocator * allocator)
1347 {
1348   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
1349
1350   alloc->mem_type = GST_GL_MEMORY_ALLOCATOR;
1351   alloc->mem_map = (GstMemoryMapFunction) _gl_mem_map;
1352   alloc->mem_unmap = (GstMemoryUnmapFunction) _gl_mem_unmap;
1353   alloc->mem_copy = (GstMemoryCopyFunction) _gl_mem_copy;
1354   alloc->mem_share = (GstMemoryShareFunction) _gl_mem_share;
1355   alloc->mem_is_span = (GstMemoryIsSpanFunction) _gl_mem_is_span;
1356 }
1357
1358 /**
1359  * gst_gl_memory_init:
1360  *
1361  * Initializes the GL Memory allocator. It is safe to call this function
1362  * multiple times.  This must be called before any other GstGLMemory operation.
1363  */
1364 void
1365 gst_gl_memory_init (void)
1366 {
1367   static volatile gsize _init = 0;
1368
1369   if (g_once_init_enter (&_init)) {
1370     GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glmemory", 0, "OpenGL Memory");
1371
1372     _gl_allocator = g_object_new (gst_gl_allocator_get_type (), NULL);
1373
1374     gst_allocator_register (GST_GL_MEMORY_ALLOCATOR,
1375         gst_object_ref (_gl_allocator));
1376     g_once_init_leave (&_init, 1);
1377   }
1378 }
1379
1380 /**
1381  * gst_is_gl_memory:
1382  * @mem:a #GstMemory
1383  * 
1384  * Returns: whether the memory at @mem is a #GstGLMemory
1385  */
1386 gboolean
1387 gst_is_gl_memory (GstMemory * mem)
1388 {
1389   return mem != NULL && mem->allocator == _gl_allocator;
1390 }
1391
1392 /**
1393  * gst_gl_memory_setup_buffer:
1394  * @context: a #GstGLContext
1395  * @info: a #GstVideoInfo
1396  * @valign: the #GstVideoAlignment applied to @info
1397  * @buffer: a #GstBuffer
1398  *
1399  * Adds the required #GstGLMemory<!--  -->s with the correct configuration to
1400  * @buffer based on @info. This version handles padding through @valign.
1401  *
1402  * Returns: whether the memory's were sucessfully added.
1403  */
1404 gboolean
1405 gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
1406     GstVideoAlignment * valign, GstBuffer * buffer)
1407 {
1408   GstGLMemory *gl_mem[GST_VIDEO_MAX_PLANES] = { NULL, };
1409   guint n_mem, i;
1410
1411   n_mem = GST_VIDEO_INFO_N_PLANES (info);
1412
1413   for (i = 0; i < n_mem; i++) {
1414     gl_mem[i] = (GstGLMemory *) gst_gl_memory_alloc (context, info, i, valign);
1415     if (gl_mem[i] == NULL)
1416       return FALSE;
1417
1418     gst_buffer_append_memory (buffer, (GstMemory *) gl_mem[i]);
1419   }
1420
1421   gst_buffer_add_video_meta_full (buffer, 0,
1422       GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
1423       GST_VIDEO_INFO_HEIGHT (info), n_mem, info->offset, info->stride);
1424
1425   return TRUE;
1426 }
1427
1428 /**
1429  * gst_gl_memory_setup_wrapped:
1430  * @context: a #GstGLContext
1431  * @info: a #GstVideoInfo
1432  * @valign: a #GstVideoInfo
1433  * @data: a list of per plane data pointers
1434  * @textures: (transfer out): a list of #GstGLMemory
1435  *
1436  * Wraps per plane data pointer in @data into the corresponding entry in
1437  * @textures based on @info and padding from @valign.
1438  *
1439  * Returns: whether the memory's were sucessfully created.
1440  */
1441 gboolean
1442 gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info,
1443     GstVideoAlignment * valign, gpointer data[GST_VIDEO_MAX_PLANES],
1444     GstGLMemory * textures[GST_VIDEO_MAX_PLANES])
1445 {
1446   gint i;
1447
1448   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1449     textures[i] = (GstGLMemory *) gst_gl_memory_wrapped (context, info, i,
1450         valign, data[i], NULL, NULL);
1451   }
1452
1453   return TRUE;
1454 }