diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types index 83eebef20d..d0d844a363 100644 --- a/docs/libs/gst-plugins-bad-libs.types +++ b/docs/libs/gst-plugins-bad-libs.types @@ -27,6 +27,7 @@ gst_insert_bin_get_type gst_gl_buffer_allocator_get_type +gst_gl_memory_allocator_get_type gst_gl_base_filter_get_type gst_gl_buffer_pool_get_type gst_gl_color_convert_get_type diff --git a/ext/gl/gstgldownloadelement.c b/ext/gl/gstgldownloadelement.c index 94a6e7a8eb..917bdc7aab 100644 --- a/ext/gl/gstgldownloadelement.c +++ b/ext/gl/gstgldownloadelement.c @@ -176,7 +176,8 @@ gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt, if (gst_is_gl_memory (mem)) { if (!features || gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)) { - gst_gl_memory_download_transfer ((GstGLMemory *) mem); + if (gst_is_gl_memory_pbo (mem)) + gst_gl_memory_pbo_download_transfer ((GstGLMemoryPBO *) mem); } } } diff --git a/ext/gl/gstgloverlay.c b/ext/gl/gstgloverlay.c index a152fc22cb..c26135237c 100644 --- a/ext/gl/gstgloverlay.c +++ b/ext/gl/gstgloverlay.c @@ -696,7 +696,7 @@ gst_gl_overlay_load_jpeg (GstGLOverlay * overlay, FILE * fp) gst_video_info_align (&v_info, &v_align); overlay->image_memory = (GstGLMemory *) - gst_gl_memory_alloc (GST_GL_BASE_FILTER (overlay)->context, + gst_gl_memory_pbo_alloc (GST_GL_BASE_FILTER (overlay)->context, GST_GL_TEXTURE_TARGET_2D, NULL, &v_info, 0, &v_align); if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info, @@ -801,7 +801,7 @@ gst_gl_overlay_load_png (GstGLOverlay * overlay, FILE * fp) gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, width, height); overlay->image_memory = (GstGLMemory *) - gst_gl_memory_alloc (GST_GL_BASE_FILTER (overlay)->context, + gst_gl_memory_pbo_alloc (GST_GL_BASE_FILTER (overlay)->context, GST_GL_TEXTURE_TARGET_2D, NULL, &v_info, 0, NULL); if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info, diff --git a/ext/qt/gstqsgtexture.cc b/ext/qt/gstqsgtexture.cc index 0986a82bb6..13208c05f2 100644 --- a/ext/qt/gstqsgtexture.cc +++ b/ext/qt/gstqsgtexture.cc @@ -111,7 +111,7 @@ GstQSGTexture::bind () mem = gst_buffer_peek_memory (this->buffer_, 0); g_assert (gst_is_gl_memory (mem)); - context = ((GstGLBaseBuffer *)mem)->context; + context = ((GstGLBaseMemory *)mem)->context; sync_meta = gst_buffer_get_gl_sync_meta (this->sync_buffer_); if (!sync_meta) diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index bc83ce387f..77baef79cb 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -16,8 +16,10 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \ gstglbasememory.c \ gstglbuffer.c \ gstglmemory.c \ + gstglmemorypbo.c \ gstglbufferpool.c \ gstglfilter.c \ + gstglformat.c \ gstglbasefilter.c \ gstglshader.c \ gstglshaderstrings.c \ @@ -46,8 +48,10 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gstglbasememory.h \ gstglbuffer.h \ gstglmemory.h \ + gstglmemorypbo.h \ gstglbufferpool.h \ gstglfilter.h \ + gstglformat.h \ gstglbasefilter.h \ gstglshader.h \ gstglshaderstrings.h \ diff --git a/gst-libs/gst/gl/gl.h b/gst-libs/gst/gl/gl.h index 44dbbecf5b..ae05c499e4 100644 --- a/gst-libs/gst/gl/gl.h +++ b/gst-libs/gst/gl/gl.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h index 0f45d0ee1d..860483d126 100644 --- a/gst-libs/gst/gl/gstgl_fwd.h +++ b/gst-libs/gst/gl/gstgl_fwd.h @@ -52,8 +52,12 @@ typedef struct _GstGLBufferAllocator GstGLBufferAllocator; typedef struct _GstGLBufferAllocatorClass GstGLBufferAllocatorClass; typedef struct _GstGLMemory GstGLMemory; -typedef struct _GstGLAllocator GstGLAllocator; -typedef struct _GstGLAllocatorClass GstGLAllocatorClass; +typedef struct _GstGLMemoryAllocator GstGLMemoryAllocator; +typedef struct _GstGLMemoryAllocatorClass GstGLMemoryAllocatorClass; + +typedef struct _GstGLMemoryPBO GstGLMemoryPBO; +typedef struct _GstGLMemoryPBOAllocator GstGLMemoryPBOAllocator; +typedef struct _GstGLMemoryPBOAllocatorClass GstGLMemoryPBOAllocatorClass; typedef struct _GstGLSLStage GstGLSLStage; typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate; diff --git a/gst-libs/gst/gl/gstglbufferpool.c b/gst-libs/gst/gl/gstglbufferpool.c index 12261f0367..a2de0cfc72 100644 --- a/gst-libs/gst/gl/gstglbufferpool.c +++ b/gst-libs/gst/gl/gstglbufferpool.c @@ -120,10 +120,7 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) if (priv->allocator) gst_object_unref (priv->allocator); - if (!allocator) { - gst_gl_memory_init (); - priv->allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); - } else { + if (allocator) { priv->allocator = gst_object_ref (allocator); } @@ -142,12 +139,14 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) GST_BUFFER_POOL_OPTION_GL_SYNC_META); #if GST_GL_HAVE_PLATFORM_EGL - g_assert (priv->allocator != NULL); - priv->want_eglimage = - (g_strcmp0 (priv->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0); -#else - priv->want_eglimage = FALSE; + if (priv->allocator) { + priv->want_eglimage = + (g_strcmp0 (priv->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0); + } else #endif + { + priv->want_eglimage = FALSE; + } max_align = alloc_params.align; @@ -299,7 +298,7 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, } #endif - if (!gst_gl_memory_setup_buffer (glpool->context, priv->tex_target, + if (!gst_gl_memory_pbo_setup_buffer (glpool->context, priv->tex_target, &priv->params, info, valign, buf)) goto mem_create_failed; diff --git a/gst-libs/gst/gl/gstglcolorconvert.c b/gst-libs/gst/gl/gstglcolorconvert.c index 9fd640e5b5..eaf1ad71bf 100644 --- a/gst-libs/gst/gl/gstglcolorconvert.c +++ b/gst-libs/gst/gl/gstglcolorconvert.c @@ -2013,7 +2013,7 @@ _do_convert_one_view (GstGLContext * context, GstGLColorConvert * convert, if (!convert->priv->out_tex[j]) convert->priv->out_tex[j] = - (GstGLMemory *) gst_gl_memory_alloc (context, + (GstGLMemory *) gst_gl_memory_pbo_alloc (context, convert->priv->to_texture_target, NULL, &temp_info, 0, NULL); } else { convert->priv->out_tex[j] = out_tex; @@ -2069,10 +2069,9 @@ out: res = FALSE; continue; } - gst_gl_memory_copy_into_texture (convert->priv->out_tex[j], + gst_gl_memory_copy_into (convert->priv->out_tex[j], out_tex->tex_id, convert->priv->to_texture_target, out_tex->tex_type, - mem_width, mem_height, GST_VIDEO_INFO_PLANE_STRIDE (&out_tex->info, - out_tex->plane), FALSE); + mem_width, mem_height); gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &from_info); gst_memory_unmap ((GstMemory *) out_tex, &to_info); } else { @@ -2120,7 +2119,7 @@ _do_convert (GstGLContext * context, GstGLColorConvert * convert) gst_gl_sync_meta_wait (sync_meta, convert->context); convert->outbuf = gst_buffer_new (); - if (!gst_gl_memory_setup_buffer (convert->context, + if (!gst_gl_memory_pbo_setup_buffer (convert->context, convert->priv->to_texture_target, NULL, &convert->out_info, NULL, convert->outbuf)) { convert->priv->result = FALSE; diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 10e9ef78e0..79c173662c 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -140,8 +140,8 @@ gst_gl_display_init (GstGLDisplay * display) GST_TRACE ("init %p", display); gst_gl_base_buffer_init_once (); - gst_gl_memory_init (); gst_gl_buffer_init_once (); + gst_gl_memory_pbo_init_once (); #if GST_GL_HAVE_PLATFORM_EGL gst_egl_image_memory_init (); diff --git a/gst-libs/gst/gl/gstglformat.c b/gst-libs/gst/gl/gstglformat.c new file mode 100644 index 0000000000..6d9f4a9082 --- /dev/null +++ b/gst-libs/gst/gl/gstglformat.c @@ -0,0 +1,358 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)) +#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1)) +#define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0)) +#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)) +#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)) + +#ifndef GL_RGBA8 +#define GL_RGBA8 0x8058 +#endif +#ifndef GL_RED +#define GL_RED 0x1903 +#endif +#ifndef GL_RG +#define GL_RG 0x8227 +#endif +#ifndef GL_R8 +#define GL_R8 0x8229 +#endif +#ifndef GL_RG8 +#define GL_RG8 0x822B +#endif + +static inline guint +_gl_format_n_components (guint format) +{ + switch (format) { + case GST_VIDEO_GL_TEXTURE_TYPE_RGBA: + case GL_RGBA: + return 4; + case GST_VIDEO_GL_TEXTURE_TYPE_RGB: + case GST_VIDEO_GL_TEXTURE_TYPE_RGB16: + case GL_RGB: + return 3; + case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA: + case GST_VIDEO_GL_TEXTURE_TYPE_RG: + case GL_LUMINANCE_ALPHA: + case GL_RG: + return 2; + case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE: + case GST_VIDEO_GL_TEXTURE_TYPE_R: + case GL_LUMINANCE: + case GL_RED: + return 1; + default: + return 0; + } +} + +static inline guint +_gl_type_n_components (guint type) +{ + switch (type) { + case GL_UNSIGNED_BYTE: + return 1; + case GL_UNSIGNED_SHORT_5_6_5: + return 3; + default: + g_assert_not_reached (); + return 0; + } +} + +static inline guint +_gl_type_n_bytes (guint type) +{ + switch (type) { + case GL_UNSIGNED_BYTE: + return 1; + case GL_UNSIGNED_SHORT_5_6_5: + return 2; + default: + g_assert_not_reached (); + return 0; + } +} + +guint +gst_gl_format_type_n_bytes (guint format, guint type) +{ + return _gl_format_n_components (format) / _gl_type_n_components (type) * + _gl_type_n_bytes (type); +} + +guint +gst_gl_texture_type_n_bytes (GstVideoGLTextureType tex_format) +{ + guint format, type; + + format = gst_gl_format_from_gl_texture_type (tex_format); + type = GL_UNSIGNED_BYTE; + if (tex_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + type = GL_UNSIGNED_SHORT_5_6_5; + + return gst_gl_format_type_n_bytes (format, type); +} + +guint +gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format) +{ + switch (tex_format) { + case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA: + return GL_LUMINANCE_ALPHA; + case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE: + return GL_LUMINANCE; + case GST_VIDEO_GL_TEXTURE_TYPE_RGBA: + return GL_RGBA; + case GST_VIDEO_GL_TEXTURE_TYPE_RGB: + case GST_VIDEO_GL_TEXTURE_TYPE_RGB16: + return GL_RGB; + case GST_VIDEO_GL_TEXTURE_TYPE_RG: + return GL_RG; + case GST_VIDEO_GL_TEXTURE_TYPE_R: + return GL_RED; + default: + return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; + } +} + +GstVideoGLTextureType +gst_gl_texture_type_from_format (GstGLContext * context, + GstVideoFormat v_format, guint plane) +{ + gboolean texture_rg = + gst_gl_context_check_feature (context, "GL_EXT_texture_rg") + || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0) + || gst_gl_context_check_feature (context, "GL_ARB_texture_rg") + || gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 0); + guint n_plane_components; + + switch (v_format) { + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_BGRA: + case GST_VIDEO_FORMAT_ARGB: + case GST_VIDEO_FORMAT_ABGR: + case GST_VIDEO_FORMAT_AYUV: + n_plane_components = 4; + break; + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + n_plane_components = 3; + break; + case GST_VIDEO_FORMAT_RGB16: + case GST_VIDEO_FORMAT_BGR16: + return GST_VIDEO_GL_TEXTURE_TYPE_RGB16; + case GST_VIDEO_FORMAT_GRAY16_BE: + case GST_VIDEO_FORMAT_GRAY16_LE: + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + n_plane_components = 2; + break; + case GST_VIDEO_FORMAT_NV12: + case GST_VIDEO_FORMAT_NV21: + n_plane_components = plane == 0 ? 1 : 2; + break; + case GST_VIDEO_FORMAT_GRAY8: + case GST_VIDEO_FORMAT_Y444: + case GST_VIDEO_FORMAT_Y42B: + case GST_VIDEO_FORMAT_Y41B: + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + n_plane_components = 1; + break; + default: + n_plane_components = 4; + g_assert_not_reached (); + break; + } + + switch (n_plane_components) { + case 4: + return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; + break; + case 3: + return GST_VIDEO_GL_TEXTURE_TYPE_RGB; + break; + case 2: + return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_RG : + GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA; + break; + case 1: + return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_R : + GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; + break; + default: + g_assert_not_reached (); + break; + } + + return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; +} + +guint +gst_gl_sized_gl_format_from_gl_format_type (GstGLContext * context, + guint format, guint type) +{ + gboolean ext_texture_rg = + gst_gl_context_check_feature (context, "GL_EXT_texture_rg"); + + switch (format) { + case GL_RGBA: + switch (type) { + case GL_UNSIGNED_BYTE: + return USING_GLES2 (context) + && !USING_GLES3 (context) ? GL_RGBA : GL_RGBA8; + break; + } + break; + case GL_RGB: + switch (type) { + case GL_UNSIGNED_BYTE: + return GL_RGB8; + break; + case GL_UNSIGNED_SHORT_5_6_5: + return GL_RGB; + break; + } + break; + case GL_RG: + switch (type) { + case GL_UNSIGNED_BYTE: + if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg) + return GL_RG; + return GL_RG8; + break; + } + break; + case GL_RED: + switch (type) { + case GL_UNSIGNED_BYTE: + if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg) + return GL_RED; + return GL_R8; + break; + } + break; + case GL_LUMINANCE: + return GL_LUMINANCE; + break; + case GL_LUMINANCE_ALPHA: + return GL_LUMINANCE_ALPHA; + break; + case GL_ALPHA: + return GL_ALPHA; + break; + default: + break; + } + + g_assert_not_reached (); + return 0; +} + +const gchar * +gst_gl_texture_target_to_string (GstGLTextureTarget target) +{ + switch (target) { + case GST_GL_TEXTURE_TARGET_2D: + return GST_GL_TEXTURE_TARGET_2D_STR; + case GST_GL_TEXTURE_TARGET_RECTANGLE: + return GST_GL_TEXTURE_TARGET_RECTANGLE_STR; + case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: + return GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR; + default: + return NULL; + } +} + +GstGLTextureTarget +gst_gl_texture_target_from_string (const gchar * str) +{ + if (!str) + return GST_GL_TEXTURE_TARGET_NONE; + + if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_2D_STR) == 0) + return GST_GL_TEXTURE_TARGET_2D; + if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_RECTANGLE_STR) == 0) + return GST_GL_TEXTURE_TARGET_RECTANGLE; + if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR) == 0) + return GST_GL_TEXTURE_TARGET_EXTERNAL_OES; + + return GST_GL_TEXTURE_TARGET_NONE; +} + +guint +gst_gl_texture_target_to_gl (GstGLTextureTarget target) +{ + switch (target) { + case GST_GL_TEXTURE_TARGET_2D: + return GL_TEXTURE_2D; + case GST_GL_TEXTURE_TARGET_RECTANGLE: + return GL_TEXTURE_RECTANGLE; + case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: + return GL_TEXTURE_EXTERNAL_OES; + default: + return 0; + } +} + +GstGLTextureTarget +gst_gl_texture_target_from_gl (guint target) +{ + switch (target) { + case GL_TEXTURE_2D: + return GST_GL_TEXTURE_TARGET_2D; + case GL_TEXTURE_RECTANGLE: + return GST_GL_TEXTURE_TARGET_RECTANGLE; + case GL_TEXTURE_EXTERNAL_OES: + return GST_GL_TEXTURE_TARGET_EXTERNAL_OES; + default: + return GST_GL_TEXTURE_TARGET_NONE; + } +} + +const gchar * +gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget target) +{ + switch (target) { + case GST_GL_TEXTURE_TARGET_2D: + return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_2D; + case GST_GL_TEXTURE_TARGET_RECTANGLE: + return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE; + case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: + return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_EXTERNAL_OES; + default: + return NULL; + } +} diff --git a/gst-libs/gst/gl/gstglformat.h b/gst-libs/gst/gl/gstglformat.h new file mode 100644 index 0000000000..c8e67645f4 --- /dev/null +++ b/gst-libs/gst/gl/gstglformat.h @@ -0,0 +1,58 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_GL_FORMAT_H_ +#define _GST_GL_FORMAT_H_ + +#include + +#include +#include + +#define GST_GL_TEXTURE_TARGET_2D_STR "2D" +#define GST_GL_TEXTURE_TARGET_RECTANGLE_STR "rectangle" +#define GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR "external-oes" + +#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_2D "GstBufferPoolOptionGLTextureTarget2D" +#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE "GstBufferPoolOptionGLTextureTargetRectangle" +#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_EXTERNAL_OES "GstBufferPoolOptionGLTextureTargetExternalOES" + +G_BEGIN_DECLS + +guint gst_gl_format_type_n_bytes (guint format, + guint type); +guint gst_gl_texture_type_n_bytes (GstVideoGLTextureType tex_format); +guint gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format); +GstVideoGLTextureType gst_gl_texture_type_from_format (GstGLContext * context, + GstVideoFormat v_format, + guint plane); +guint gst_gl_sized_gl_format_from_gl_format_type (GstGLContext * context, + guint format, + guint type); + +GstGLTextureTarget gst_gl_texture_target_from_string (const gchar * str); +const gchar * gst_gl_texture_target_to_string (GstGLTextureTarget target); +guint gst_gl_texture_target_to_gl (GstGLTextureTarget target); +GstGLTextureTarget gst_gl_texture_target_from_gl (guint target); +const gchar * gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget target); + +G_END_DECLS + +#endif /* _GST_GL_FORMAT_H_ */ diff --git a/gst-libs/gst/gl/gstglmemory.c b/gst-libs/gst/gl/gstglmemory.c index c8bd9179f5..51930cf552 100644 --- a/gst-libs/gst/gl/gstglmemory.c +++ b/gst-libs/gst/gl/gstglmemory.c @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2015 Matthew Waters * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,8 +26,8 @@ #include -#include "gstglmemory.h" -#include "gstglutils.h" +#include +#include /** * SECTION:gstglmemory @@ -60,50 +60,10 @@ #define GL_MEM_HEIGHT(gl_mem) _get_plane_height (&gl_mem->info, gl_mem->plane) #define GL_MEM_STRIDE(gl_mem) GST_VIDEO_INFO_PLANE_STRIDE (&gl_mem->info, gl_mem->plane) -#define CONTEXT_SUPPORTS_PBO_UPLOAD(context) \ - (gst_gl_context_check_gl_version (context, \ - GST_GL_API_OPENGL | GST_GL_API_OPENGL3, 2, 1) \ - || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)) -#define CONTEXT_SUPPORTS_PBO_DOWNLOAD(context) \ - (gst_gl_context_check_gl_version (context, \ - GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2, 3, 0)) - GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY); #define GST_CAT_DEFAULT GST_CAT_GL_MEMORY -static GstAllocator *_gl_allocator; - /* compatability definitions... */ -#ifndef GL_RGBA8 -#define GL_RGBA8 0x8058 -#endif -#ifndef GL_RED -#define GL_RED 0x1903 -#endif -#ifndef GL_RG -#define GL_RG 0x8227 -#endif -#ifndef GL_R8 -#define GL_R8 0x8229 -#endif -#ifndef GL_RG8 -#define GL_RG8 0x822B -#endif -#ifndef GL_PIXEL_PACK_BUFFER -#define GL_PIXEL_PACK_BUFFER 0x88EB -#endif -#ifndef GL_PIXEL_UNPACK_BUFFER -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#endif -#ifndef GL_STREAM_READ -#define GL_STREAM_READ 0x88E1 -#endif -#ifndef GL_STREAM_DRAW -#define GL_STREAM_DRAW 0x88E0 -#endif -#ifndef GL_STREAM_COPY -#define GL_STREAM_COPY 0x88E2 -#endif #ifndef GL_UNPACK_ROW_LENGTH #define GL_UNPACK_ROW_LENGTH 0x0CF2 #endif @@ -115,8 +75,8 @@ static GstAllocator *_gl_allocator; #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #endif -G_DEFINE_TYPE (GstGLAllocator, gst_gl_allocator, - GST_TYPE_GL_BASE_BUFFER_ALLOCATOR); +G_DEFINE_ABSTRACT_TYPE (GstGLMemoryAllocator, gst_gl_memory_allocator, + GST_TYPE_GL_BASE_MEMORY_ALLOCATOR); typedef struct { @@ -124,325 +84,14 @@ typedef struct GstGLMemory *src; GstVideoGLTextureType out_format; guint out_width, out_height; - guint out_stride; - gboolean respecify; GstGLTextureTarget tex_target; + GstVideoGLTextureType tex_type; /* inout */ guint tex_id; /* out */ gboolean result; } GstGLMemoryCopyParams; -static inline guint -_gl_format_n_components (guint format) -{ - switch (format) { - case GST_VIDEO_GL_TEXTURE_TYPE_RGBA: - case GL_RGBA: - return 4; - case GST_VIDEO_GL_TEXTURE_TYPE_RGB: - case GST_VIDEO_GL_TEXTURE_TYPE_RGB16: - case GL_RGB: - return 3; - case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA: - case GST_VIDEO_GL_TEXTURE_TYPE_RG: - case GL_LUMINANCE_ALPHA: - case GL_RG: - return 2; - case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE: - case GST_VIDEO_GL_TEXTURE_TYPE_R: - case GL_LUMINANCE: - case GL_RED: - return 1; - default: - return 0; - } -} - -static inline guint -_gl_type_n_components (guint type) -{ - switch (type) { - case GL_UNSIGNED_BYTE: - return 1; - case GL_UNSIGNED_SHORT_5_6_5: - return 3; - default: - g_assert_not_reached (); - return 0; - } -} - -static inline guint -_gl_type_n_bytes (guint type) -{ - switch (type) { - case GL_UNSIGNED_BYTE: - return 1; - case GL_UNSIGNED_SHORT_5_6_5: - return 2; - default: - g_assert_not_reached (); - return 0; - } -} - -static inline guint -_gl_format_type_n_bytes (guint format, guint type) -{ - return _gl_format_n_components (format) / _gl_type_n_components (type) * - _gl_type_n_bytes (type); -} - -static inline guint -_gl_texture_type_n_bytes (GstVideoGLTextureType tex_format) -{ - guint format, type; - - format = gst_gl_format_from_gl_texture_type (tex_format); - type = GL_UNSIGNED_BYTE; - if (tex_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) - type = GL_UNSIGNED_SHORT_5_6_5; - - return _gl_format_type_n_bytes (format, type); -} - -guint -gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format) -{ - switch (tex_format) { - case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA: - return GL_LUMINANCE_ALPHA; - case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE: - return GL_LUMINANCE; - case GST_VIDEO_GL_TEXTURE_TYPE_RGBA: - return GL_RGBA; - case GST_VIDEO_GL_TEXTURE_TYPE_RGB: - case GST_VIDEO_GL_TEXTURE_TYPE_RGB16: - return GL_RGB; - case GST_VIDEO_GL_TEXTURE_TYPE_RG: - return GL_RG; - case GST_VIDEO_GL_TEXTURE_TYPE_R: - return GL_RED; - default: - return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; - } -} - -GstVideoGLTextureType -gst_gl_texture_type_from_format (GstGLContext * context, - GstVideoFormat v_format, guint plane) -{ - gboolean texture_rg = - gst_gl_context_check_feature (context, "GL_EXT_texture_rg") - || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0) - || gst_gl_context_check_feature (context, "GL_ARB_texture_rg") - || gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 0); - guint n_plane_components; - - switch (v_format) { - case GST_VIDEO_FORMAT_RGBx: - case GST_VIDEO_FORMAT_BGRx: - case GST_VIDEO_FORMAT_xRGB: - case GST_VIDEO_FORMAT_xBGR: - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_BGRA: - case GST_VIDEO_FORMAT_ARGB: - case GST_VIDEO_FORMAT_ABGR: - case GST_VIDEO_FORMAT_AYUV: - n_plane_components = 4; - break; - case GST_VIDEO_FORMAT_RGB: - case GST_VIDEO_FORMAT_BGR: - n_plane_components = 3; - break; - case GST_VIDEO_FORMAT_RGB16: - case GST_VIDEO_FORMAT_BGR16: - return GST_VIDEO_GL_TEXTURE_TYPE_RGB16; - case GST_VIDEO_FORMAT_GRAY16_BE: - case GST_VIDEO_FORMAT_GRAY16_LE: - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - n_plane_components = 2; - break; - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_NV21: - n_plane_components = plane == 0 ? 1 : 2; - break; - case GST_VIDEO_FORMAT_GRAY8: - case GST_VIDEO_FORMAT_Y444: - case GST_VIDEO_FORMAT_Y42B: - case GST_VIDEO_FORMAT_Y41B: - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - n_plane_components = 1; - break; - default: - n_plane_components = 4; - g_assert_not_reached (); - break; - } - - switch (n_plane_components) { - case 4: - return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; - break; - case 3: - return GST_VIDEO_GL_TEXTURE_TYPE_RGB; - break; - case 2: - return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_RG : - GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA; - break; - case 1: - return texture_rg ? GST_VIDEO_GL_TEXTURE_TYPE_R : - GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; - break; - default: - g_assert_not_reached (); - break; - } - - return GST_VIDEO_GL_TEXTURE_TYPE_RGBA; -} - -guint -gst_gl_sized_gl_format_from_gl_format_type (GstGLContext * context, - guint format, guint type) -{ - gboolean ext_texture_rg = - gst_gl_context_check_feature (context, "GL_EXT_texture_rg"); - - switch (format) { - case GL_RGBA: - switch (type) { - case GL_UNSIGNED_BYTE: - return USING_GLES2 (context) - && !USING_GLES3 (context) ? GL_RGBA : GL_RGBA8; - break; - } - break; - case GL_RGB: - switch (type) { - case GL_UNSIGNED_BYTE: - return GL_RGB8; - break; - case GL_UNSIGNED_SHORT_5_6_5: - return GL_RGB; - break; - } - break; - case GL_RG: - switch (type) { - case GL_UNSIGNED_BYTE: - if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg) - return GL_RG; - return GL_RG8; - break; - } - break; - case GL_RED: - switch (type) { - case GL_UNSIGNED_BYTE: - if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg) - return GL_RED; - return GL_R8; - break; - } - break; - case GL_LUMINANCE: - return GL_LUMINANCE; - break; - case GL_LUMINANCE_ALPHA: - return GL_LUMINANCE_ALPHA; - break; - case GL_ALPHA: - return GL_ALPHA; - break; - default: - break; - } - - g_assert_not_reached (); - return 0; -} - -const gchar * -gst_gl_texture_target_to_string (GstGLTextureTarget target) -{ - switch (target) { - case GST_GL_TEXTURE_TARGET_2D: - return GST_GL_TEXTURE_TARGET_2D_STR; - case GST_GL_TEXTURE_TARGET_RECTANGLE: - return GST_GL_TEXTURE_TARGET_RECTANGLE_STR; - case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: - return GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR; - default: - return NULL; - } -} - -GstGLTextureTarget -gst_gl_texture_target_from_string (const gchar * str) -{ - if (!str) - return GST_GL_TEXTURE_TARGET_NONE; - - if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_2D_STR) == 0) - return GST_GL_TEXTURE_TARGET_2D; - if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_RECTANGLE_STR) == 0) - return GST_GL_TEXTURE_TARGET_RECTANGLE; - if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR) == 0) - return GST_GL_TEXTURE_TARGET_EXTERNAL_OES; - - return GST_GL_TEXTURE_TARGET_NONE; -} - -guint -gst_gl_texture_target_to_gl (GstGLTextureTarget target) -{ - switch (target) { - case GST_GL_TEXTURE_TARGET_2D: - return GL_TEXTURE_2D; - case GST_GL_TEXTURE_TARGET_RECTANGLE: - return GL_TEXTURE_RECTANGLE; - case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: - return GL_TEXTURE_EXTERNAL_OES; - default: - return 0; - } -} - -GstGLTextureTarget -gst_gl_texture_target_from_gl (guint target) -{ - switch (target) { - case GL_TEXTURE_2D: - return GST_GL_TEXTURE_TARGET_2D; - case GL_TEXTURE_RECTANGLE: - return GST_GL_TEXTURE_TARGET_RECTANGLE; - case GL_TEXTURE_EXTERNAL_OES: - return GST_GL_TEXTURE_TARGET_EXTERNAL_OES; - default: - return GST_GL_TEXTURE_TARGET_NONE; - } -} - -const gchar * -gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget target) -{ - switch (target) { - case GST_GL_TEXTURE_TARGET_2D: - return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_2D; - case GST_GL_TEXTURE_TARGET_RECTANGLE: - return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE; - case GST_GL_TEXTURE_TARGET_EXTERNAL_OES: - return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_EXTERNAL_OES; - default: - return NULL; - } -} - static inline guint _get_plane_width (GstVideoInfo * info, guint plane) { @@ -467,96 +116,6 @@ _get_plane_height (GstVideoInfo * info, guint plane) return GST_VIDEO_INFO_HEIGHT (info); } -typedef struct _GenTexture -{ - guint width, height; - GLenum gl_target; - GLenum gl_format; - GLenum gl_type; - guint result; -} GenTexture; - -/* find the difference between the start of the plane and where the video - * data starts in the plane */ -static gsize -_find_plane_frame_start (GstGLMemory * gl_mem) -{ - gsize plane_start; - gint i; - - /* find the start of the plane data including padding */ - plane_start = 0; - for (i = 0; i < gl_mem->plane; i++) { - plane_start += - gst_gl_get_plane_data_size (&gl_mem->info, &gl_mem->valign, i); - } - - /* offset between the plane data start and where the video frame starts */ - return (GST_VIDEO_INFO_PLANE_OFFSET (&gl_mem->info, - gl_mem->plane)) - plane_start + gl_mem->mem.mem.offset; -} - -static void -_upload_memory (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize) -{ - GstGLContext *context = gl_mem->mem.context; - const GstGLFuncs *gl; - GLenum gl_format, gl_type, gl_target; - gpointer data; - gsize plane_start; - - if ((gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_UPLOAD) == 0) - return; - - gl = context->gl_vtable; - - gl_type = GL_UNSIGNED_BYTE; - if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) - gl_type = GL_UNSIGNED_SHORT_5_6_5; - - gl_format = gst_gl_format_from_gl_texture_type (gl_mem->tex_type); - gl_target = gst_gl_texture_target_to_gl (gl_mem->tex_target); - - if (USING_OPENGL (context) || USING_GLES3 (context) - || USING_OPENGL3 (context)) { - gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length); - } else if (USING_GLES2 (context)) { - gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length); - } - - GST_LOG ("upload for texture id:%u, with pbo %u %ux%u", - gl_mem->tex_id, gl_mem->mem.id, gl_mem->tex_width, - GL_MEM_HEIGHT (gl_mem)); - - /* find the start of the plane data including padding */ - plane_start = _find_plane_frame_start (gl_mem); - - if (gl_mem->mem.id && CONTEXT_SUPPORTS_PBO_UPLOAD (context)) { - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, gl_mem->mem.id); - data = (void *) plane_start; - } else { - data = (gpointer) ((gintptr) plane_start + (gintptr) gl_mem->mem.data); - } - - gl->BindTexture (gl_target, gl_mem->tex_id); - gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->tex_width, - GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, data); - - if (gl_mem->mem.id && CONTEXT_SUPPORTS_PBO_UPLOAD (context)) - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0); - - /* Reset to default values */ - if (USING_OPENGL (context) || USING_GLES3 (context)) { - gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0); - } else if (USING_GLES2 (context)) { - gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4); - } - - gl->BindTexture (gl_target, 0); - - gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; -} - static inline void _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context) { @@ -567,7 +126,7 @@ _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context) gl_mem->unpack_length = 1; gl_mem->tex_width = GL_MEM_WIDTH (gl_mem); - n_gl_bytes = _gl_texture_type_n_bytes (gl_mem->tex_type); + n_gl_bytes = gst_gl_texture_type_n_bytes (gl_mem->tex_type); if (n_gl_bytes == 0) { GST_ERROR ("Unsupported texture type %d", gl_mem->tex_type); return; @@ -585,8 +144,8 @@ _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context) ((GL_MEM_WIDTH (gl_mem) * n_gl_bytes) + j - 1) & ~(j - 1); if (round_up_j == GL_MEM_STRIDE (gl_mem)) { - GST_LOG ("Found alignment of %u based on width " - "(with plane width:%u, plane stride:%u and pixel stride:%u. " + GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on " + "width (with plane width:%u, plane stride:%u and pixel stride:%u. " "RU%u(%u*%u) = %u)", j, GL_MEM_WIDTH (gl_mem), GL_MEM_STRIDE (gl_mem), n_gl_bytes, j, GL_MEM_WIDTH (gl_mem), n_gl_bytes, round_up_j); @@ -608,8 +167,8 @@ _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context) guint round_up_j = ((GL_MEM_STRIDE (gl_mem)) + j - 1) & ~(j - 1); if (round_up_j == (GL_MEM_STRIDE (gl_mem))) { - GST_LOG ("Found alignment of %u based on " - "stride (with plane stride:%u and pixel stride:%u. " + GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based " + "on stride (with plane stride:%u and pixel stride:%u. " "RU%u(%u) = %u)", j, GL_MEM_STRIDE (gl_mem), n_gl_bytes, j, GL_MEM_STRIDE (gl_mem), round_up_j); @@ -624,11 +183,10 @@ _calculate_unpack_length (GstGLMemory * gl_mem, GstGLContext * context) } if (j < n_gl_bytes) { - GST_ERROR - ("Failed to find matching alignment. Image may " - "look corrupted. plane width:%u, plane stride:%u and pixel " - "stride:%u", GL_MEM_WIDTH (gl_mem), GL_MEM_STRIDE (gl_mem), - n_gl_bytes); + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to find matching " + "alignment. Image may look corrupted. plane width:%u, " + "plane stride:%u and pixel stride:%u", GL_MEM_WIDTH (gl_mem), + GL_MEM_STRIDE (gl_mem), n_gl_bytes); } } } @@ -670,10 +228,9 @@ _new_texture (GstGLContext * context, guint target, guint internal_format, } static gboolean -_gl_mem_create (GstGLMemory * gl_mem, GError ** error) +_gl_tex_create (GstGLMemory * gl_mem, GError ** error) { GstGLContext *context = gl_mem->mem.context; - const GstGLFuncs *gl = context->gl_vtable; GLenum internal_format; GLenum tex_format; GLenum tex_type; @@ -683,9 +240,6 @@ _gl_mem_create (GstGLMemory * gl_mem, GError ** error) if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) tex_type = GL_UNSIGNED_SHORT_5_6_5; - GST_TRACE ("Generating texture format:%u type:%u dimensions:%ux%u", - tex_format, tex_type, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem)); - internal_format = gst_gl_sized_gl_format_from_gl_format_type (context, tex_format, tex_type); @@ -695,31 +249,20 @@ _gl_mem_create (GstGLMemory * gl_mem, GError ** error) _new_texture (context, gst_gl_texture_target_to_gl (gl_mem->tex_target), internal_format, tex_format, tex_type, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem)); - } - GST_LOG ("generated texture id:%d", gl_mem->tex_id); - - if (USING_OPENGL (context) || USING_OPENGL3 (context) - || USING_GLES3 (context)) { - /* FIXME: lazy init this for resource constrained platforms - * Will need to fix pbo detection based on the existence of the mem.id then */ - gl->GenBuffers (1, &gl_mem->mem.id); - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, gl_mem->mem.id); - gl->BufferData (GL_PIXEL_UNPACK_BUFFER, gl_mem->mem.mem.maxsize, NULL, - GL_STREAM_DRAW); - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0); - GST_LOG ("generated pbo %u", gl_mem->mem.id); + GST_TRACE ("Generating texture id:%u format:%u type:%u dimensions:%ux%u", + gl_mem->tex_id, tex_format, tex_type, gl_mem->tex_width, + GL_MEM_HEIGHT (gl_mem)); } return TRUE; } -static void -_gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent, - GstGLContext * context, GstGLTextureTarget target, - GstAllocationParams * params, GstVideoInfo * info, - GstVideoAlignment * valign, guint plane, gpointer user_data, - GDestroyNotify notify) +void +gst_gl_memory_init (GstGLMemory * mem, GstAllocator * allocator, + GstMemory * parent, GstGLContext * context, GstGLTextureTarget target, + GstAllocationParams * params, GstVideoInfo * info, guint plane, + GstVideoAlignment * valign, GDestroyNotify notify, gpointer user_data) { const gchar *target_str; gsize size; @@ -749,47 +292,27 @@ _gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent, size = gst_gl_get_plane_data_size (info, valign, plane); - /* we always operate on 2D textures unless we're dealing with wrapped textures */ mem->tex_target = target; mem->tex_type = gst_gl_texture_type_from_format (context, GST_VIDEO_INFO_FORMAT (info), plane); mem->plane = plane; - mem->notify = notify; - mem->user_data = user_data; _calculate_unpack_length (mem, context); - /* calls _gl_mem_create() */ - gst_gl_base_buffer_init ((GstGLBaseBuffer *) mem, allocator, parent, context, - params, size); + gst_gl_base_memory_init ((GstGLBaseMemory *) mem, allocator, parent, context, + params, size, notify, user_data); target_str = gst_gl_texture_target_to_string (target); - GST_DEBUG ("new GL texture context:%" GST_PTR_FORMAT " memory:%p target:%s " - "format:%u dimensions:%ux%u stride:%u size:%" G_GSIZE_FORMAT, context, - mem, target_str, mem->tex_type, mem->tex_width, GL_MEM_HEIGHT (mem), - GL_MEM_STRIDE (mem), mem->mem.mem.size); + GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture context:%" + GST_PTR_FORMAT " memory:%p target:%s format:%u dimensions:%ux%u " + "stride:%u size:%" G_GSIZE_FORMAT, context, mem, target_str, + mem->tex_type, mem->tex_width, GL_MEM_HEIGHT (mem), GL_MEM_STRIDE (mem), + mem->mem.mem.size); } -static GstGLMemory * -_gl_mem_new (GstAllocator * allocator, GstMemory * parent, - GstGLContext * context, GstGLTextureTarget target, - GstAllocationParams * params, GstVideoInfo * info, - GstVideoAlignment * valign, guint plane, gpointer user_data, - GDestroyNotify notify) -{ - GstGLMemory *mem; - mem = g_slice_new0 (GstGLMemory); - mem->texture_wrapped = FALSE; - - _gl_mem_init (mem, allocator, parent, context, target, params, info, valign, - plane, user_data, notify); - - return mem; -} - -static gboolean -_gl_mem_read_pixels (GstGLMemory * gl_mem, gpointer read_pointer) +gboolean +gst_gl_memory_read_pixels (GstGLMemory * gl_mem, gpointer read_pointer) { GstGLContext *context = gl_mem->mem.context; const GstGLFuncs *gl = context->gl_vtable; @@ -825,64 +348,8 @@ _gl_mem_read_pixels (GstGLMemory * gl_mem, gpointer read_pointer) return TRUE; } -static gboolean -_read_pixels_to_pbo (GstGLMemory * gl_mem) -{ - const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable; - - if (!gl_mem->mem.id || !CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.context) - || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE - || gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA) - /* unsupported */ - return FALSE; - - if (gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) { - /* copy texture data into into the pbo and map that */ - gsize plane_start = _find_plane_frame_start (gl_mem); - - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, gl_mem->mem.id); - - if (!_gl_mem_read_pixels (gl_mem, (gpointer) plane_start)) { - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0); - return FALSE; - } - - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0); - gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; - } - - return TRUE; -} - static gpointer -_pbo_download_transfer (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) -{ - GstGLBaseBufferAllocatorClass *alloc_class; - gpointer data = NULL; - - alloc_class = - GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class); - - /* texture -> pbo */ - if (info->flags & GST_MAP_READ - && gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) { - GST_CAT_TRACE (GST_CAT_GL_MEMORY, "attempting download of texture %u " - "using pbo %u", gl_mem->tex_id, gl_mem->mem.id); - - if (!_read_pixels_to_pbo (gl_mem)) - return NULL; - } - - /* get a cpu accessible mapping from the pbo */ - gl_mem->mem.target = GL_PIXEL_PACK_BUFFER; - /* pbo -> data */ - data = alloc_class->map_buffer ((GstGLBaseBuffer *) gl_mem, info, size); - - return data; -} - -static gpointer -_gl_mem_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info, +_gl_tex_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) { GstGLContext *context = gl_mem->mem.context; @@ -900,7 +367,8 @@ _gl_mem_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info, return NULL; if (info->flags & GST_MAP_READ - && gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) { + && GST_MEMORY_FLAG_IS_SET (gl_mem, + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { guint format, type; guint target; @@ -922,17 +390,19 @@ _gl_mem_download_get_tex_image (GstGLMemory * gl_mem, GstMapInfo * info, } static gpointer -_gl_mem_download_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info, +_gl_tex_download_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) { if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize) return NULL; if (info->flags & GST_MAP_READ - && gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) { - GST_CAT_TRACE (GST_CAT_GL_MEMORY, "attempting download of texture %u " - "using glReadPixels", gl_mem->tex_id); - if (!_gl_mem_read_pixels (gl_mem, gl_mem->mem.data)) + && GST_MEMORY_FLAG_IS_SET (gl_mem, + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { + GST_CAT_TRACE (GST_CAT_GL_MEMORY, + "attempting download of texture %u " "using glReadPixels", + gl_mem->tex_id); + if (!gst_gl_memory_read_pixels (gl_mem, gl_mem->mem.data)) return NULL; } @@ -940,157 +410,197 @@ _gl_mem_download_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info, } static gpointer -_gl_mem_map_cpu_access (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) +_gl_tex_map_cpu_access (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) { gpointer data = NULL; - gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) gl_mem); - - if (!data && gl_mem->mem.id - && CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.context)) - data = _pbo_download_transfer (gl_mem, info, size); - if (!data) - data = _gl_mem_download_get_tex_image (gl_mem, info, size); + if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (gl_mem))) + return NULL; if (!data) - data = _gl_mem_download_read_pixels (gl_mem, info, size); + data = _gl_tex_download_get_tex_image (gl_mem, info, size); + + if (!data) + data = _gl_tex_download_read_pixels (gl_mem, info, size); return data; } -static gpointer -_gl_mem_map_buffer (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize) +static void +_upload_cpu_write (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize) { - GstGLBaseBufferAllocatorClass *alloc_class; + GstGLContext *context = gl_mem->mem.context; + const GstGLFuncs *gl; + GLenum gl_format, gl_type, gl_target; + gpointer data; + gsize plane_start; + + if (!GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) + return; + + gl = context->gl_vtable; + + gl_type = GL_UNSIGNED_BYTE; + if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + gl_type = GL_UNSIGNED_SHORT_5_6_5; + + gl_format = gst_gl_format_from_gl_texture_type (gl_mem->tex_type); + gl_target = gst_gl_texture_target_to_gl (gl_mem->tex_target); + + if (USING_OPENGL (context) || USING_GLES3 (context) + || USING_OPENGL3 (context)) { + gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->unpack_length); + } else if (USING_GLES2 (context)) { + gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->unpack_length); + } + + GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, %ux%u", + gl_mem->tex_id, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem)); + + /* find the start of the plane data including padding */ + plane_start = + gst_gl_get_plane_start (&gl_mem->info, &gl_mem->valign, + gl_mem->plane) + gl_mem->mem.mem.offset; + + data = (gpointer) ((gintptr) plane_start + (gintptr) gl_mem->mem.data); + + gl->BindTexture (gl_target, gl_mem->tex_id); + gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->tex_width, + GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, data); + + /* Reset to default values */ + if (USING_OPENGL (context) || USING_GLES3 (context)) { + gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0); + } else if (USING_GLES2 (context)) { + gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4); + } + + gl->BindTexture (gl_target, 0); +} + +static gpointer +_default_gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize size) +{ + if ((info->flags & GST_MAP_GL) == GST_MAP_GL) { + _upload_cpu_write (gl_mem, info, size); + return &gl_mem->tex_id; + } else { + return _gl_tex_map_cpu_access (gl_mem, info, size); + } +} + +static gpointer +_gl_tex_map (GstGLMemory * gl_mem, GstMapInfo * info, gsize maxsize) +{ + GstGLMemoryAllocatorClass *alloc_class; gpointer data; - alloc_class = - GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class); + alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator); if ((info->flags & GST_MAP_GL) == GST_MAP_GL) { if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) return &gl_mem->tex_id; - - if ((info->flags & GST_MAP_READ) == GST_MAP_READ) { - GST_TRACE ("mapping GL texture:%u for reading", gl_mem->tex_id); - - if (gl_mem->mem.id && CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.context)) { - gl_mem->mem.target = GL_PIXEL_UNPACK_BUFFER; - /* data -> pbo */ - alloc_class->map_buffer ((GstGLBaseBuffer *) gl_mem, info, maxsize); - } - /* pbo -> texture */ - _upload_memory (gl_mem, info, maxsize); - } - - if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE) { - GST_TRACE ("mapping GL texture:%u for writing", gl_mem->tex_id); - gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; - } - gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; - - data = &gl_mem->tex_id; } else { /* not GL */ if (gl_mem->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot map External OES textures"); return NULL; } - - data = _gl_mem_map_cpu_access (gl_mem, info, maxsize); - if (info->flags & GST_MAP_WRITE) - gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; - gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; } + g_return_val_if_fail (alloc_class->map != NULL, NULL); + data = alloc_class->map (GST_GL_BASE_MEMORY_CAST (gl_mem), info, maxsize); + return data; } static void -_gl_mem_unmap_cpu_access (GstGLMemory * gl_mem, GstMapInfo * info) +_default_gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info) { - GstGLBaseBufferAllocatorClass *alloc_class; - const GstGLFuncs *gl; - - alloc_class = - GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class); - gl = gl_mem->mem.context->gl_vtable; - - if (!gl_mem->mem.id) - /* PBO's not supported */ - return; - - gl_mem->mem.target = GL_PIXEL_PACK_BUFFER; - alloc_class->unmap_buffer ((GstGLBaseBuffer *) gl_mem, info); - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0); } static void -_gl_mem_unmap_buffer (GstGLMemory * gl_mem, GstMapInfo * info) +_gl_tex_unmap (GstGLMemory * gl_mem, GstMapInfo * info) { - if ((info->flags & GST_MAP_GL) == 0) { - _gl_mem_unmap_cpu_access (gl_mem, info); - if (info->flags & GST_MAP_WRITE) - gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; - } else { - if (info->flags & GST_MAP_WRITE) - gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; - } + GstGLMemoryAllocatorClass *alloc_class; + + alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (gl_mem->mem.mem.allocator); + g_return_if_fail (alloc_class->unmap != NULL); + + alloc_class->unmap (GST_GL_BASE_MEMORY_CAST (gl_mem), info); } -static void -_gl_mem_copy_thread (GstGLContext * context, gpointer data) +gboolean +gst_gl_memory_copy_teximage (GstGLMemory * src, guint tex_id, + GstGLTextureTarget out_target, GstVideoGLTextureType out_tex_type, + gint out_width, gint out_height) { const GstGLFuncs *gl; - GstGLMemoryCopyParams *copy_params; - GstGLMemory *src; - guint tex_id; - guint out_tex_target; - GLuint fboId; - gsize out_width, out_height, out_stride; - GLuint out_gl_format, out_gl_type; - GLuint in_gl_format, in_gl_type; - gsize in_size, out_size; + guint out_gl_format, out_tex_target; + GstMapInfo sinfo; + guint src_tex_id; + guint fbo; - copy_params = (GstGLMemoryCopyParams *) data; - src = copy_params->src; - tex_id = copy_params->tex_id; - out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target); - out_width = copy_params->out_width; - out_height = copy_params->out_height; - out_stride = copy_params->out_stride; - - gl = context->gl_vtable; - out_gl_format = gst_gl_format_from_gl_texture_type (copy_params->out_format); - out_gl_type = GL_UNSIGNED_BYTE; - if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) - out_gl_type = GL_UNSIGNED_SHORT_5_6_5; - in_gl_format = gst_gl_format_from_gl_texture_type (src->tex_type); - in_gl_type = GL_UNSIGNED_BYTE; - if (src->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) - in_gl_type = GL_UNSIGNED_SHORT_5_6_5; + gl = src->mem.context->gl_vtable; + out_tex_target = gst_gl_texture_target_to_gl (out_target); + out_gl_format = gst_gl_format_from_gl_texture_type (out_tex_type); if (!gl->GenFramebuffers) { - gst_gl_context_set_error (context, - "Context, EXT_framebuffer_object not supported"); + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Framebuffer objects not supported"); goto error; } - in_size = GL_MEM_HEIGHT (src) * GL_MEM_STRIDE (src); - out_size = out_height * out_stride; - - if (copy_params->respecify) { - if (in_size != out_size) { - GST_ERROR ("Cannot copy between textures with backing data of different" - "sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size, - out_size); - goto error; - } + if (!gst_memory_map (GST_MEMORY_CAST (src), &sinfo, + GST_MAP_READ | GST_MAP_GL)) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, + "Failed to map source memory for copying"); + goto error; } + src_tex_id = *(guint *) sinfo.data; - if (!tex_id) { - guint internal_format; - guint out_gl_type; + GST_CAT_LOG (GST_CAT_GL_MEMORY, "copying memory %p, tex %u into " + "texture %i", src, src_tex_id, tex_id); + /* FIXME: try and avoid creating and destroying fbo's every copy... */ + /* create a framebuffer object */ + gl->GenFramebuffers (1, &fbo); + gl->BindFramebuffer (GL_FRAMEBUFFER, fbo); + + gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + gst_gl_texture_target_to_gl (src->tex_target), src_tex_id, 0); + +// if (!gst_gl_context_check_framebuffer_status (src->context)) +// goto fbo_error; + + gl->BindTexture (out_tex_target, tex_id); + gl->CopyTexImage2D (out_tex_target, 0, out_gl_format, 0, 0, out_width, + out_height, 0); + + gl->BindTexture (out_tex_target, 0); + gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + + gl->DeleteFramebuffers (1, &fbo); + + gst_memory_unmap (GST_MEMORY_CAST (src), &sinfo); + + return TRUE; + +error: + return FALSE; +} + +static void +_gl_tex_copy_thread (GstGLContext * context, gpointer data) +{ + GstGLMemoryCopyParams *copy_params; + + copy_params = (GstGLMemoryCopyParams *) data; + + if (!copy_params->tex_id) { + guint internal_format, out_gl_format, out_gl_type, out_tex_target; + + out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target); + out_gl_format = + gst_gl_format_from_gl_texture_type (copy_params->src->tex_type); out_gl_type = GL_UNSIGNED_BYTE; if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) out_gl_type = GL_UNSIGNED_SHORT_5_6_5; @@ -1099,251 +609,98 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data) gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format, out_gl_type); - tex_id = + copy_params->tex_id = _new_texture (context, out_tex_target, internal_format, out_gl_format, out_gl_type, copy_params->out_width, copy_params->out_height); } - if (!tex_id) { - GST_WARNING ("Could not create GL texture with context:%p", context); - } - - GST_LOG ("copying memory %p, tex %u into texture %i", - src, src->tex_id, tex_id); - - /* FIXME: try and avoid creating and destroying fbo's every copy... */ - /* create a framebuffer object */ - gl->GenFramebuffers (1, &fboId); - gl->BindFramebuffer (GL_FRAMEBUFFER, fboId); - - gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - gst_gl_texture_target_to_gl (src->tex_target), src->tex_id, 0); - -// if (!gst_gl_context_check_framebuffer_status (src->context)) -// goto fbo_error; - - gl->BindTexture (out_tex_target, tex_id); - if (copy_params->respecify) { - if (!gl->GenBuffers || !src->mem.id) { - gst_gl_context_set_error (context, "Cannot reinterpret texture contents " - "without pixel buffer objects"); - gl->BindTexture (out_tex_target, 0); - goto fbo_error; - } - - if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2 - && (in_gl_format != GL_RGBA || in_gl_type != GL_UNSIGNED_BYTE)) { - gst_gl_context_set_error (context, "Cannot copy non RGBA/UNSIGNED_BYTE " - "textures on GLES2"); - gl->BindTexture (out_tex_target, 0); - goto fbo_error; - } - - GST_TRACE ("copying texture data with size of %u*%u*%u", - _gl_format_type_n_bytes (in_gl_format, in_gl_type), src->tex_width, - GL_MEM_HEIGHT (src)); - - /* copy tex */ - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, src->mem.id); - gl->BufferData (GL_PIXEL_PACK_BUFFER, in_size, NULL, GL_STREAM_COPY); - gl->ReadPixels (0, 0, src->tex_width, GL_MEM_HEIGHT (src), in_gl_format, - in_gl_type, 0); - gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0); - - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, src->mem.id); - gl->TexSubImage2D (out_tex_target, 0, 0, 0, out_width, out_height, - out_gl_format, out_gl_type, 0); - - gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0); - } else { /* different sizes */ - gl->CopyTexImage2D (out_tex_target, 0, out_gl_format, 0, 0, out_width, - out_height, 0); - } - - gl->BindTexture (out_tex_target, 0); - gl->BindFramebuffer (GL_FRAMEBUFFER, 0); - - gl->DeleteFramebuffers (1, &fboId); - - copy_params->tex_id = tex_id; - copy_params->result = TRUE; - - return; - -/* ERRORS */ -fbo_error: - { - gl->DeleteFramebuffers (1, &fboId); - - copy_params->tex_id = 0; - copy_params->result = FALSE; - return; - } - -error: - { - copy_params->result = FALSE; - return; - } + copy_params->result = gst_gl_memory_copy_teximage (copy_params->src, + copy_params->tex_id, copy_params->tex_target, copy_params->tex_type, + copy_params->out_width, copy_params->out_height); } static GstMemory * -_gl_mem_copy (GstGLMemory * src, gssize offset, gssize size) +_default_gl_tex_copy (GstGLMemory * src, gssize offset, gssize size) { - GstGLAllocator *allocator = (GstGLAllocator *) src->mem.mem.allocator; - GstMemory *ret = NULL; + return NULL; +} + +static GstMemory * +_gl_tex_copy (GstGLMemory * src, gssize offset, gssize size) +{ + GstGLMemoryAllocatorClass *alloc_class; + + alloc_class = GST_GL_MEMORY_ALLOCATOR_GET_CLASS (src->mem.mem.allocator); if (src->tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures"); return NULL; } - /* If not doing a full copy, then copy to sysmem, the 2D represention of the - * texture would become wrong */ - if (offset > 0 || size < src->mem.mem.size) { - ret = allocator->fallback_mem_copy (&src->mem.mem, offset, size); - } else if (GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)) { - GstAllocationParams params = { 0, src->mem.mem.align, 0, 0 }; - GstGLMemory *dest; - - dest = _gl_mem_new (src->mem.mem.allocator, NULL, src->mem.context, - src->tex_target, ¶ms, &src->info, &src->valign, src->plane, NULL, - NULL); - dest = (GstGLMemory *) gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) - dest); - - if (dest == NULL) { - GST_WARNING ("Could not copy GL Memory"); - goto done; - } - - memcpy (dest->mem.data, (guint8 *) src->mem.data + src->mem.mem.offset, - src->mem.mem.size); - GST_MINI_OBJECT_FLAG_SET (dest, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD); - dest->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; - ret = (GstMemory *) dest; - } else { - GstAllocationParams params = { 0, src->mem.mem.align, 0, 0 }; - GstGLMemoryCopyParams copy_params; - GstGLMemory *dest; - - copy_params.src = src; - copy_params.tex_id = 0; - copy_params.out_format = src->tex_type; - copy_params.tex_target = src->tex_target; - copy_params.out_width = src->tex_width; - copy_params.out_height = GL_MEM_HEIGHT (src); - copy_params.out_stride = GL_MEM_STRIDE (src); - copy_params.respecify = FALSE; - - _gl_mem_copy_thread (src->mem.context, ©_params); - - if (!copy_params.result) { - GST_WARNING ("Could not copy GL Memory"); - goto done; - } - - dest = g_slice_new0 (GstGLMemory); - /* don't create our own texture */ - dest->texture_wrapped = TRUE; - _gl_mem_init (dest, src->mem.mem.allocator, NULL, src->mem.context, - src->tex_target, ¶ms, &src->info, &src->valign, src->plane, NULL, - NULL); - dest->texture_wrapped = FALSE; - - dest->tex_id = copy_params.tex_id; - dest->tex_target = copy_params.tex_target; - dest = (GstGLMemory *) gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) - dest); - GST_MINI_OBJECT_FLAG_SET (dest, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD); - dest->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; - ret = (GstMemory *) dest; - } - -done: - return ret; + g_return_val_if_fail (alloc_class->copy, NULL); + return (GstMemory *) alloc_class->copy (GST_GL_BASE_MEMORY_CAST (src), offset, + size); } static GstMemory * -_gl_mem_alloc (GstAllocator * allocator, gsize size, +_gl_tex_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params) { - g_warning ("use gst_gl_memory_alloc () to allocate from this " - "GstGLMemory allocator"); + g_warning ("Subclass needs to override GstAllocatorClass::alloc"); return NULL; } static void -_gl_mem_destroy (GstGLMemory * gl_mem) +_gl_tex_destroy (GstGLMemory * gl_mem) { const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable; if (gl_mem->tex_id && !gl_mem->texture_wrapped) gl->DeleteTextures (1, &gl_mem->tex_id); - - if (gl_mem->mem.id) - gl->DeleteBuffers (1, &gl_mem->mem.id); } static void -_gl_mem_free (GstAllocator * allocator, GstMemory * mem) +gst_gl_memory_allocator_class_init (GstGLMemoryAllocatorClass * klass) { - GstGLMemory *gl_mem = (GstGLMemory *) mem; - - GST_ALLOCATOR_CLASS (gst_gl_allocator_parent_class)->free (allocator, mem); - - if (gl_mem->notify) - gl_mem->notify (gl_mem->user_data); - - g_slice_free (GstGLMemory, gl_mem); -} - -static void -gst_gl_allocator_class_init (GstGLAllocatorClass * klass) -{ - GstGLBaseBufferAllocatorClass *gl_base; + GstGLBaseMemoryAllocatorClass *gl_base; GstAllocatorClass *allocator_class; - gl_base = (GstGLBaseBufferAllocatorClass *) klass; + gl_base = (GstGLBaseMemoryAllocatorClass *) klass; allocator_class = (GstAllocatorClass *) klass; - gl_base->create = (GstGLBaseBufferAllocatorCreateFunction) _gl_mem_create; - gl_base->map_buffer = - (GstGLBaseBufferAllocatorMapBufferFunction) _gl_mem_map_buffer; - gl_base->unmap_buffer = - (GstGLBaseBufferAllocatorUnmapBufferFunction) _gl_mem_unmap_buffer; - gl_base->copy = (GstGLBaseBufferAllocatorCopyFunction) _gl_mem_copy; - gl_base->destroy = (GstGLBaseBufferAllocatorDestroyFunction) _gl_mem_destroy; + klass->map = (GstGLBaseMemoryAllocatorMapFunction) _default_gl_tex_map; + klass->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _default_gl_tex_unmap; + klass->copy = (GstGLBaseMemoryAllocatorCopyFunction) _default_gl_tex_copy; - allocator_class->alloc = _gl_mem_alloc; - allocator_class->free = _gl_mem_free; + gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_tex_create; + gl_base->map = (GstGLBaseMemoryAllocatorMapFunction) _gl_tex_map; + gl_base->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _gl_tex_unmap; + gl_base->copy = (GstGLBaseMemoryAllocatorCopyFunction) _gl_tex_copy; + gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_tex_destroy; + + allocator_class->alloc = _gl_tex_alloc; } static void -gst_gl_allocator_init (GstGLAllocator * allocator) +gst_gl_memory_allocator_init (GstGLMemoryAllocator * allocator) { GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); - /* Keep the fallback copy function around, we will need it when copying with - * at an offset or smaller size */ - allocator->fallback_mem_copy = alloc->mem_copy; - - alloc->mem_type = GST_GL_MEMORY_ALLOCATOR; + alloc->mem_type = GST_GL_MEMORY_ALLOCATOR_NAME; GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); } /** - * gst_gl_memory_copy_into_texture: + * gst_gl_memory_copy_into: * @gl_mem:a #GstGLMemory * @tex_id:OpenGL texture id - * @tex_type: a #GstVideoGLTextureType + * @taget: the #GstGLTextureTarget + * @tex_type: the #GstVideoGLTextureType * @width: width of @tex_id * @height: height of @tex_id - * @stride: stride of the backing texture data - * @respecify: whether to copy the data or copy per texel * * Copies @gl_mem into the texture specfified by @tex_id. The format of @tex_id * is specified by @tex_type, @width and @height. @@ -1362,182 +719,25 @@ gst_gl_allocator_init (GstGLAllocator * allocator) * Returns: Whether the copy suceeded */ gboolean -gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id, +gst_gl_memory_copy_into (GstGLMemory * gl_mem, guint tex_id, GstGLTextureTarget target, GstVideoGLTextureType tex_type, gint width, - gint height, gint stride, gboolean respecify) + gint height) { GstGLMemoryCopyParams copy_params; copy_params.src = gl_mem; - copy_params.tex_target = target; copy_params.tex_id = tex_id; - copy_params.out_format = tex_type; + copy_params.tex_target = target; + copy_params.tex_type = tex_type; copy_params.out_width = width; copy_params.out_height = height; - copy_params.out_stride = stride; - copy_params.respecify = respecify; - gst_gl_context_thread_add (gl_mem->mem.context, _gl_mem_copy_thread, + gst_gl_context_thread_add (gl_mem->mem.context, _gl_tex_copy_thread, ©_params); return copy_params.result; } -/** - * gst_gl_memory_wrapped_texture: - * @context: a #GstGLContext - * @texture_id: the GL texture handle - * @texture_target: the GL texture target - * @info: the #GstVideoInfo of the memory - * @plane: The plane this memory will represent - * @user_data: user data - * @notify: Destroy callback for the user data - * - * Wraps a texture handle into a #GstGLMemory. - * - * Returns: a newly allocated #GstGLMemory - */ -GstGLMemory * -gst_gl_memory_wrapped_texture (GstGLContext * context, - guint texture_id, GstGLTextureTarget target, - GstVideoInfo * info, guint plane, GstVideoAlignment * valign, - gpointer user_data, GDestroyNotify notify) -{ - GstGLMemory *mem; - - mem = g_slice_new0 (GstGLMemory); - - mem->tex_id = texture_id; - mem->texture_wrapped = TRUE; - - _gl_mem_init (mem, _gl_allocator, NULL, context, target, NULL, info, valign, - plane, user_data, notify); - - mem = (GstGLMemory *) gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) mem); - GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD); - mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD; - - return mem; -} - -/** - * gst_gl_memory_alloc: - * @context:a #GstGLContext - * @params: a #GstAllocationParams - * @info: the #GstVideoInfo of the memory - * @plane: the plane this memory will represent - * @valign: the #GstVideoAlignment applied to @info - * - * Allocated a new #GstGlMemory. - * - * Returns: a #GstMemory object with a GL texture specified by @vinfo - * from @context - */ -GstMemory * -gst_gl_memory_alloc (GstGLContext * context, GstGLTextureTarget target, - GstAllocationParams * params, GstVideoInfo * info, guint plane, - GstVideoAlignment * valign) -{ - GstGLMemory *mem; - - mem = - _gl_mem_new (_gl_allocator, NULL, context, target, params, info, valign, - plane, NULL, NULL); - mem = (GstGLMemory *) gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) mem); - - return (GstMemory *) mem; -} - -/** - * gst_gl_memory_wrapped: - * @context:a #GstGLContext - * @info: the #GstVideoInfo of the memory and data - * @plane: the plane this memory will represent - * @valign: the #GstVideoAlignment applied to @info - * @data: the data to wrap - * @user_data: data called with for @notify - * @notify: function called with @user_data when @data needs to be freed - * - * Wrapped @data into a #GstGLMemory. This version will account for padding - * added to the allocation and expressed through @valign. - * - * Returns: a #GstGLMemory object with a GL texture specified by @v_info - * from @context and contents specified by @data - */ -GstGLMemory * -gst_gl_memory_wrapped (GstGLContext * context, GstGLTextureTarget target, - GstVideoInfo * info, guint plane, GstVideoAlignment * valign, gpointer data, - gpointer user_data, GDestroyNotify notify) -{ - GstGLMemory *mem; - - mem = _gl_mem_new (_gl_allocator, NULL, context, target, NULL, info, valign, - plane, user_data, notify); - if (!mem) - return NULL; - - mem->mem.data = data; - - GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD); - mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD; - - return mem; -} - -static void -_download_transfer (GstGLContext * context, GstGLMemory * gl_mem) -{ - GstGLBaseBuffer *mem = (GstGLBaseBuffer *) gl_mem; - - g_mutex_lock (&mem->lock); - if (_read_pixels_to_pbo (gl_mem)) - GST_CAT_TRACE (GST_CAT_GL_MEMORY, "optimistic download of texture %u " - "using pbo %u", gl_mem->tex_id, gl_mem->mem.id); - g_mutex_unlock (&mem->lock); -} - -void -gst_gl_memory_download_transfer (GstGLMemory * gl_mem) -{ - g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem)); - - gst_gl_context_thread_add (gl_mem->mem.context, - (GstGLContextThreadFunc) _download_transfer, gl_mem); -} - -static void -_upload_transfer (GstGLContext * context, GstGLMemory * gl_mem) -{ - GstGLBaseBufferAllocatorClass *alloc_class; - GstGLBaseBuffer *mem = (GstGLBaseBuffer *) gl_mem; - GstMapInfo info; - - alloc_class = - GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class); - - info.flags = GST_MAP_READ | GST_MAP_GL; - info.memory = (GstMemory *) mem; - /* from gst_memory_map() */ - info.size = mem->mem.size; - info.maxsize = mem->mem.maxsize - mem->mem.offset; - - g_mutex_lock (&mem->lock); - mem->target = GL_PIXEL_UNPACK_BUFFER; - alloc_class->map_buffer (mem, &info, mem->mem.maxsize); - alloc_class->unmap_buffer (mem, &info); - g_mutex_unlock (&mem->lock); -} - -void -gst_gl_memory_upload_transfer (GstGLMemory * gl_mem) -{ - g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem)); - - if (CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.context)) - gst_gl_context_thread_add (gl_mem->mem.context, - (GstGLContextThreadFunc) _upload_transfer, gl_mem); -} - gint gst_gl_memory_get_texture_width (GstGLMemory * gl_mem) { @@ -1554,24 +754,46 @@ gst_gl_memory_get_texture_height (GstGLMemory * gl_mem) return _get_plane_height (&gl_mem->info, gl_mem->plane); } +GstVideoGLTextureType +gst_gl_memory_get_texture_type (GstGLMemory * gl_mem) +{ + g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0); + + return gl_mem->tex_type; +} + +GstGLTextureTarget +gst_gl_memory_get_texture_target (GstGLMemory * gl_mem) +{ + g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0); + + return gl_mem->tex_target; +} + +guint +gst_gl_memory_get_texture_id (GstGLMemory * gl_mem) +{ + g_return_val_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem), 0); + + return gl_mem->tex_id; +} + /** - * gst_gl_memory_init: + * gst_gl_memory_init_once: * - * Initializes the GL Memory allocator. It is safe to call this function + * Initializes the GL Base Texture allocator. It is safe to call this function * multiple times. This must be called before any other GstGLMemory operation. */ void -gst_gl_memory_init (void) +gst_gl_memory_init_once (void) { static volatile gsize _init = 0; if (g_once_init_enter (&_init)) { - GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glmemory", 0, "OpenGL Memory"); + gst_gl_base_memory_init_once (); - _gl_allocator = g_object_new (gst_gl_allocator_get_type (), NULL); - - gst_allocator_register (GST_GL_MEMORY_ALLOCATOR, - gst_object_ref (_gl_allocator)); + GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glbasetexture", 0, + "OpenGL Base Texture Memory"); g_once_init_leave (&_init, 1); } } @@ -1586,87 +808,6 @@ gboolean gst_is_gl_memory (GstMemory * mem) { return mem != NULL && mem->allocator != NULL - && g_type_is_a (G_OBJECT_TYPE (mem->allocator), GST_TYPE_GL_ALLOCATOR); -} - -/** - * gst_gl_memory_setup_buffer: - * @context: a #GstGLContext - * @params: a #GstAllocationParams - * @info: a #GstVideoInfo - * @valign: the #GstVideoAlignment applied to @info - * @buffer: a #GstBuffer - * - * Adds the required #GstGLMemorys with the correct configuration to - * @buffer based on @info. This version handles padding through @valign. - * - * Returns: whether the memory's were sucessfully added. - */ -gboolean -gst_gl_memory_setup_buffer (GstGLContext * context, GstGLTextureTarget target, - GstAllocationParams * params, GstVideoInfo * info, - GstVideoAlignment * valign, GstBuffer * buffer) -{ - GstGLMemory *gl_mem[GST_VIDEO_MAX_PLANES] = { NULL, }; - guint n_mem, i, v, views; - - n_mem = GST_VIDEO_INFO_N_PLANES (info); - - if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) == - GST_VIDEO_MULTIVIEW_MODE_SEPARATED) - views = info->views; - else - views = 1; - - for (v = 0; v < views; v++) { - for (i = 0; i < n_mem; i++) { - gl_mem[i] = - (GstGLMemory *) gst_gl_memory_alloc (context, target, params, info, i, - valign); - if (gl_mem[i] == NULL) - return FALSE; - - gst_buffer_append_memory (buffer, (GstMemory *) gl_mem[i]); - } - - gst_buffer_add_video_meta_full (buffer, v, - GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info), - GST_VIDEO_INFO_HEIGHT (info), n_mem, info->offset, info->stride); - } - - return TRUE; -} - -/** - * gst_gl_memory_setup_wrapped: - * @context: a #GstGLContext - * @info: a #GstVideoInfo - * @valign: a #GstVideoInfo - * @data: a list of per plane data pointers - * @textures: (transfer out): a list of #GstGLMemory - * @user_data: user data for the destroy function - * @notify: A function called each time a memory is freed - * - * Wraps per plane data pointer in @data into the corresponding entry in - * @textures based on @info and padding from @valign. Note that the @notify - * will be called as many time as there is planes. - * - * Returns: whether the memory's were sucessfully created. - */ -gboolean -gst_gl_memory_setup_wrapped (GstGLContext * context, GstGLTextureTarget target, - GstVideoInfo * info, GstVideoAlignment * valign, - gpointer data[GST_VIDEO_MAX_PLANES], - GstGLMemory * textures[GST_VIDEO_MAX_PLANES], gpointer user_data, - GDestroyNotify notify) -{ - gint i; - - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) { - textures[i] = - (GstGLMemory *) gst_gl_memory_wrapped (context, target, info, i, valign, - data[i], user_data, notify); - } - - return TRUE; + && g_type_is_a (G_OBJECT_TYPE (mem->allocator), + GST_TYPE_GL_MEMORY_ALLOCATOR); } diff --git a/gst-libs/gst/gl/gstglmemory.h b/gst-libs/gst/gl/gstglmemory.h index fe8593d99a..de026971cf 100644 --- a/gst-libs/gst/gl/gstglmemory.h +++ b/gst-libs/gst/gl/gstglmemory.h @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2015 Matthew Waters * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,39 +26,27 @@ #include #include -#include -#include +#include G_BEGIN_DECLS -#define GST_TYPE_GL_ALLOCATOR (gst_gl_allocator_get_type()) -GType gst_gl_allocator_get_type(void); +#define GST_TYPE_GL_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_type()) +GType gst_gl_memory_allocator_get_type(void); -#define GST_IS_GL_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_ALLOCATOR)) -#define GST_IS_GL_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_ALLOCATOR)) -#define GST_GL_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_ALLOCATOR, GstGLAllocatorClass)) -#define GST_GL_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_ALLOCATOR, GstGLAllocator)) -#define GST_GL_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_ALLOCATOR, GstGLAllocatorClass)) -#define GST_GL_ALLOCATOR_CAST(obj) ((GstGLAllocator *)(obj)) +#define GST_IS_GL_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_MEMORY_ALLOCATOR)) +#define GST_IS_GL_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_MEMORY_ALLOCATOR)) +#define GST_GL_MEMORY_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_MEMORY_ALLOCATOR, GstGLMemoryAllocatorClass)) +#define GST_GL_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_MEMORY_ALLOCATOR, GstGLMemoryAllocator)) +#define GST_GL_MEMORY_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_MEMORY_ALLOCATOR, GstGLMemoryAllocatorClass)) +#define GST_GL_MEMORY_ALLOCATOR_CAST(obj) ((GstGLMemoryAllocator *)(obj)) -typedef enum _GstGLMemoryTransfer -{ - /* force a transfer between the texture and the PBO (if available) */ - GST_GL_MEMORY_TRANSFER_NEED_UPLOAD = (1 << 0), - GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD = (1 << 1), -} GstGLMemoryTransfer; +#define GST_GL_MEMORY_CAST(obj) ((GstGLMemory *) obj) -#define GST_GL_MEMORY_ADD_TRANSFER(mem,state) ((GstGLMemory *)mem)->transfer_state |= state - -#define GST_GL_TEXTURE_TARGET_2D_STR "2D" -#define GST_GL_TEXTURE_TARGET_RECTANGLE_STR "rectangle" -#define GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR "external-oes" - -#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_2D "GstBufferPoolOptionGLTextureTarget2D" -#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE "GstBufferPoolOptionGLTextureTargetRectangle" -#define GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_EXTERNAL_OES "GstBufferPoolOptionGLTextureTargetExternalOES" - -const gchar * gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget target); +#define GST_CAPS_FEATURE_MEMORY_GL_MEMORY "memory:GLMemory" +#define GST_GL_MEMORY_VIDEO_FORMATS_STR \ + "{ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, " \ + "AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, " \ + "GRAY8, GRAY16_LE, GRAY16_BE }" /** * GstGLMemory: @@ -76,129 +64,92 @@ const gchar * gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget ta */ struct _GstGLMemory { - GstGLBaseBuffer mem; + GstGLBaseMemory mem; - guint tex_id; - GstGLTextureTarget tex_target; - GstVideoGLTextureType tex_type; - GstVideoInfo info; - GstVideoAlignment valign; - guint plane; - gfloat tex_scaling[2]; + guint tex_id; + GstGLTextureTarget tex_target; + GstVideoGLTextureType tex_type; + GstVideoInfo info; + GstVideoAlignment valign; + guint plane; + gfloat tex_scaling[2]; - /* */ - GstGLMemoryTransfer transfer_state; - gboolean texture_wrapped; - GDestroyNotify notify; - gpointer user_data; - guint unpack_length; - guint tex_width; + /* */ + gboolean texture_wrapped; + guint unpack_length; + guint tex_width; }; -#define GST_CAPS_FEATURE_MEMORY_GL_MEMORY "memory:GLMemory" -#define GST_GL_MEMORY_VIDEO_FORMATS_STR \ - "{ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, " \ - "AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, " \ - "GRAY8, GRAY16_LE, GRAY16_BE }" +/** + * GstGLMemoryAllocator + * + * Opaque #GstGLMemoryAllocator struct + */ +struct _GstGLMemoryAllocator +{ + GstGLBaseMemoryAllocator parent; +}; /** - * GST_GL_MEMORY_ALLOCATOR: + * GstGLMemoryAllocatorClass: + * + * The #GstGLMemoryAllocatorClass only contains private data + */ +struct _GstGLMemoryAllocatorClass +{ + GstGLBaseMemoryAllocatorClass parent_class; + + GstGLBaseMemoryAllocatorMapFunction map; + GstGLBaseMemoryAllocatorCopyFunction copy; + GstGLBaseMemoryAllocatorUnmapFunction unmap; +}; + +#include + +/** + * GST_GL_MEMORY_ALLOCATOR_NAME: * * The name of the GL memory allocator */ -#define GST_GL_MEMORY_ALLOCATOR "GLMemory" +#define GST_GL_MEMORY_ALLOCATOR_NAME "GLMemory" -void gst_gl_memory_init (void); -gboolean gst_is_gl_memory (GstMemory * mem); +void gst_gl_memory_init_once (void); +gboolean gst_is_gl_memory (GstMemory * mem); -GstMemory * gst_gl_memory_alloc (GstGLContext * context, - GstGLTextureTarget target, - GstAllocationParams *params, - GstVideoInfo * info, - guint plane, - GstVideoAlignment *valign); -GstGLMemory * gst_gl_memory_wrapped (GstGLContext * context, - GstGLTextureTarget target, - GstVideoInfo * info, - guint plane, - GstVideoAlignment *valign, - gpointer data, - gpointer user_data, - GDestroyNotify notify); -GstGLMemory * gst_gl_memory_wrapped_texture (GstGLContext * context, - guint texture_id, - GstGLTextureTarget target, - GstVideoInfo * info, - guint plane, - GstVideoAlignment *valign, - gpointer user_data, - GDestroyNotify notify); +void gst_gl_memory_init (GstGLMemory * mem, + GstAllocator * allocator, + GstMemory * parent, + GstGLContext * context, + GstGLTextureTarget target, + GstAllocationParams *params, + GstVideoInfo * info, + guint plane, + GstVideoAlignment *valign, + GDestroyNotify notify, + gpointer user_data); -void gst_gl_memory_download_transfer (GstGLMemory * gl_mem); -void gst_gl_memory_upload_transfer (GstGLMemory * gl_mem); +gboolean gst_gl_memory_copy_into (GstGLMemory *gl_mem, + guint tex_id, + GstGLTextureTarget target, + GstVideoGLTextureType tex_type, + gint width, + gint height); +gboolean gst_gl_memory_copy_teximage (GstGLMemory * src, + guint tex_id, + GstGLTextureTarget out_target, + GstVideoGLTextureType out_tex_type, + gint width, + gint height); -gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, - guint tex_id, - GstGLTextureTarget target, - GstVideoGLTextureType tex_type, - gint width, - gint height, - gint stride, - gboolean respecify); +gboolean gst_gl_memory_read_pixels (GstGLMemory * gl_mem, + gpointer read_pointer); -gboolean gst_gl_memory_setup_buffer (GstGLContext * context, - GstGLTextureTarget target, - GstAllocationParams * params, - GstVideoInfo * info, - GstVideoAlignment *valign, - GstBuffer * buffer); -gboolean gst_gl_memory_setup_wrapped (GstGLContext * context, - GstGLTextureTarget target, - GstVideoInfo * info, - GstVideoAlignment *valign, - gpointer data[GST_VIDEO_MAX_PLANES], - GstGLMemory *textures[GST_VIDEO_MAX_PLANES], - gpointer user_data, - GDestroyNotify notify); - -gint gst_gl_memory_get_texture_width (GstGLMemory * gl_mem); -gint gst_gl_memory_get_texture_height (GstGLMemory * gl_mem); - -/* utility functions */ -GstVideoGLTextureType gst_gl_texture_type_from_format (GstGLContext *context, - GstVideoFormat v_format, - guint plane); -guint gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format); -guint gst_gl_sized_gl_format_from_gl_format_type (GstGLContext * context, - guint format, - guint type); - -const gchar * gst_gl_texture_target_to_string (GstGLTextureTarget target); -GstGLTextureTarget gst_gl_texture_target_from_string (const gchar * str); -GstGLTextureTarget gst_gl_texture_target_from_gl (guint target); -guint gst_gl_texture_target_to_gl (GstGLTextureTarget target); - - -/** - * GstGLAllocator - * - * Opaque #GstGLAllocator struct - */ -struct _GstGLAllocator -{ - GstGLBaseBufferAllocator parent; - GstMemoryCopyFunction fallback_mem_copy; -}; - -/** - * GstGLAllocatorClass: - * - * The #GstGLAllocatorClass only contains private data - */ -struct _GstGLAllocatorClass -{ - GstGLBaseBufferAllocatorClass parent_class; -}; +/* accessors */ +gint gst_gl_memory_get_texture_width (GstGLMemory * gl_mem); +gint gst_gl_memory_get_texture_height (GstGLMemory * gl_mem); +GstVideoGLTextureType gst_gl_memory_get_texture_type (GstGLMemory * gl_mem); +GstGLTextureTarget gst_gl_memory_get_texture_target (GstGLMemory * gl_mem); +guint gst_gl_memory_get_texture_id (GstGLMemory * gl_mem); G_END_DECLS diff --git a/gst-libs/gst/gl/gstglmemorypbo.c b/gst-libs/gst/gl/gstglmemorypbo.c new file mode 100644 index 0000000000..6ef0e3968b --- /dev/null +++ b/gst-libs/gst/gl/gstglmemorypbo.c @@ -0,0 +1,1030 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2015 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +#include + +/** + * SECTION:gstglmemorypbo + * @short_description: memory subclass for GL textures + * @see_also: #GstMemory, #GstAllocator, #GstGLBufferPool + * + * GstGLMemoryPBO is a #GstGLMemory subclass providing support for the mapping of + * GL textures. + * + * #GstGLMemoryPBO is created through gst_gl_memory_pbo_alloc() or system memory can + * be wrapped through gst_gl_memory_pbo_wrapped(). + * + * Data is uploaded or downloaded from the GPU as is necessary. + */ + +/* Implementation notes + * + * PBO transfer's are implemented using GstGLBuffer. We just need to + * ensure that the texture data is written/read to/from before/after calling + * map (mem->pbo, READ) which performs the pbo buffer transfer. + */ + +#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)) +#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1)) +#define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0)) +#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)) +#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)) + +#define GL_MEM_WIDTH(gl_mem) _get_plane_width (&gl_mem->mem.info, gl_mem->mem.plane) +#define GL_MEM_HEIGHT(gl_mem) _get_plane_height (&gl_mem->mem.info, gl_mem->mem.plane) +#define GL_MEM_STRIDE(gl_mem) GST_VIDEO_INFO_PLANE_STRIDE (&gl_mem->mem.info, gl_mem->mem.plane) + +#define CONTEXT_SUPPORTS_PBO_UPLOAD(context) \ + (gst_gl_context_check_gl_version (context, \ + GST_GL_API_OPENGL | GST_GL_API_OPENGL3, 2, 1) \ + || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)) +#define CONTEXT_SUPPORTS_PBO_DOWNLOAD(context) \ + (gst_gl_context_check_gl_version (context, \ + GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2, 3, 0)) + +GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY); +#define GST_CAT_DEFAULT GST_CAT_GL_MEMORY + +static GstAllocator *_gl_allocator; + +/* compatability definitions... */ +#ifndef GL_PIXEL_PACK_BUFFER +#define GL_PIXEL_PACK_BUFFER 0x88EB +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#endif +#ifndef GL_STREAM_READ +#define GL_STREAM_READ 0x88E1 +#endif +#ifndef GL_STREAM_DRAW +#define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_STREAM_COPY +#define GL_STREAM_COPY 0x88E2 +#endif +#ifndef GL_UNPACK_ROW_LENGTH +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#endif + +#ifndef GL_TEXTURE_RECTANGLE +#define GL_TEXTURE_RECTANGLE 0x84F5 +#endif +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + +#define parent_class gst_gl_memory_pbo_allocator_parent_class +G_DEFINE_TYPE (GstGLMemoryPBOAllocator, gst_gl_memory_pbo_allocator, + GST_TYPE_GL_MEMORY_ALLOCATOR); + +typedef struct +{ + /* in */ + GstGLMemoryPBO *src; + GstVideoGLTextureType out_format; + guint out_width, out_height; + guint out_stride; + gboolean respecify; + GstGLTextureTarget tex_target; + /* inout */ + guint tex_id; + /* out */ + gboolean result; +} GstGLMemoryPBOCopyParams; + +static inline guint +_get_plane_width (GstVideoInfo * info, guint plane) +{ + if (GST_VIDEO_INFO_IS_YUV (info)) + /* For now component width and plane width are the same and the + * plane-component mapping matches + */ + return GST_VIDEO_INFO_COMP_WIDTH (info, plane); + else /* RGB, GRAY */ + return GST_VIDEO_INFO_WIDTH (info); +} + +static inline guint +_get_plane_height (GstVideoInfo * info, guint plane) +{ + if (GST_VIDEO_INFO_IS_YUV (info)) + /* For now component width and plane width are the same and the + * plane-component mapping matches + */ + return GST_VIDEO_INFO_COMP_HEIGHT (info, plane); + else /* RGB, GRAY */ + return GST_VIDEO_INFO_HEIGHT (info); +} + +static void +_upload_pbo_memory (GstGLMemoryPBO * gl_mem, GstMapInfo * info, + GstGLBuffer * pbo, GstMapInfo * pbo_info) +{ + GstGLContext *context = gl_mem->mem.mem.context; + const GstGLFuncs *gl; + guint gl_format, gl_type, gl_target; + guint pbo_id; + gsize plane_start; + + if (!GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) + return; + + g_return_if_fail (CONTEXT_SUPPORTS_PBO_UPLOAD (context)); + + gl = context->gl_vtable; + pbo_id = *(guint *) pbo_info->data; + + gl_type = GL_UNSIGNED_BYTE; + if (gl_mem->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + gl_type = GL_UNSIGNED_SHORT_5_6_5; + + gl_format = gst_gl_format_from_gl_texture_type (gl_mem->mem.tex_type); + gl_target = gst_gl_texture_target_to_gl (gl_mem->mem.tex_target); + + if (USING_OPENGL (context) || USING_GLES3 (context) + || USING_OPENGL3 (context)) { + gl->PixelStorei (GL_UNPACK_ROW_LENGTH, gl_mem->mem.unpack_length); + } else if (USING_GLES2 (context)) { + gl->PixelStorei (GL_UNPACK_ALIGNMENT, gl_mem->mem.unpack_length); + } + + GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, with pbo %u %ux%u", + gl_mem->mem.tex_id, pbo_id, gl_mem->mem.tex_width, + GL_MEM_HEIGHT (gl_mem)); + + /* find the start of the plane data including padding */ + plane_start = + gst_gl_get_plane_start (&gl_mem->mem.info, &gl_mem->mem.valign, + gl_mem->mem.plane) + GST_MEMORY_CAST (gl_mem)->offset; + + gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo_id); + gl->BindTexture (gl_target, gl_mem->mem.tex_id); + gl->TexSubImage2D (gl_target, 0, 0, 0, gl_mem->mem.tex_width, + GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, (void *) plane_start); + gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0); + gl->BindTexture (gl_target, 0); + + /* Reset to default values */ + if (USING_OPENGL (context) || USING_GLES3 (context)) { + gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0); + } else if (USING_GLES2 (context)) { + gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4); + } +} + +static guint +_new_texture (GstGLContext * context, guint target, guint internal_format, + guint format, guint type, guint width, guint height) +{ + const GstGLFuncs *gl = context->gl_vtable; + guint tex_id; + + gl->GenTextures (1, &tex_id); + gl->BindTexture (target, tex_id); + if (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE) + gl->TexImage2D (target, 0, internal_format, width, height, 0, format, type, + NULL); + + gl->TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + gl->BindTexture (target, 0); + + return tex_id; +} + +static gboolean +_gl_mem_create (GstGLMemoryPBO * gl_mem, GError ** error) +{ + GstGLContext *context = gl_mem->mem.mem.context; + GstGLBaseMemoryAllocatorClass *alloc_class; + + alloc_class = GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class); + if (!alloc_class->create ((GstGLBaseMemory *) gl_mem, error)) + return FALSE; + + if (USING_OPENGL (context) || USING_OPENGL3 (context) + || USING_GLES3 (context)) { + GstAllocationParams params = { 0, GST_MEMORY_CAST (gl_mem)->align, 0, 0 }; + + /* FIXME: lazy init this for resource constrained platforms + * Will need to fix pbo detection based on the existence of the mem.id then */ + gl_mem->pbo = gst_gl_buffer_alloc (context, GL_PIXEL_UNPACK_BUFFER, + GL_STREAM_DRAW, ¶ms, GST_MEMORY_CAST (gl_mem)->size); + GST_CAT_LOG (GST_CAT_GL_MEMORY, "generated pbo %u", gl_mem->pbo->id); + } + + return TRUE; +} + +static void +_gl_mem_init (GstGLMemoryPBO * mem, GstAllocator * allocator, + GstMemory * parent, GstGLContext * context, GstGLTextureTarget target, + GstAllocationParams * params, GstVideoInfo * info, + GstVideoAlignment * valign, guint plane, gpointer user_data, + GDestroyNotify notify) +{ + gst_gl_memory_init ((GstGLMemory *) mem, allocator, parent, + context, target, params, info, plane, valign, notify, user_data); +} + +static GstGLMemoryPBO * +_gl_mem_new (GstAllocator * allocator, GstMemory * parent, + GstGLContext * context, GstGLTextureTarget target, + GstAllocationParams * params, GstVideoInfo * info, + GstVideoAlignment * valign, guint plane, gpointer user_data, + GDestroyNotify notify) +{ + GstGLMemoryPBO *mem; + mem = g_slice_new0 (GstGLMemoryPBO); + mem->mem.texture_wrapped = FALSE; + + _gl_mem_init (mem, allocator, parent, context, target, params, info, valign, + plane, user_data, notify); + + return mem; +} + +static gboolean +_read_pixels_to_pbo (GstGLMemoryPBO * gl_mem) +{ + if (!gl_mem->pbo || !CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.mem.context) + || gl_mem->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE + || gl_mem->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA) + /* unsupported */ + return FALSE; + + if (GST_MEMORY_FLAG_IS_SET (gl_mem, + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { + /* copy texture data into into the pbo and map that */ + gsize plane_start; + GstMapInfo pbo_info; + + plane_start = + gst_gl_get_plane_start (&gl_mem->mem.info, &gl_mem->mem.valign, + gl_mem->mem.plane) + GST_MEMORY_CAST (gl_mem)->offset; + + gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; + if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info, + GST_MAP_WRITE | GST_MAP_GL)) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo for writing"); + return FALSE; + } + + if (!gst_gl_memory_read_pixels ((GstGLMemory *) gl_mem, + (gpointer) plane_start)) { + gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); + return FALSE; + } + + gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); + } + + return TRUE; +} + +static gpointer +_pbo_download_transfer (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize size) +{ + GstMapInfo *pbo_info; + + /* texture -> pbo */ + if (info->flags & GST_MAP_READ + && GST_MEMORY_FLAG_IS_SET (gl_mem, + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { + GST_CAT_TRACE (GST_CAT_GL_MEMORY, + "attempting download of texture %u " "using pbo %u", gl_mem->mem.tex_id, + gl_mem->pbo->id); + + if (!_read_pixels_to_pbo (gl_mem)) + return NULL; + } + + pbo_info = g_new0 (GstMapInfo, 1); + + /* pbo -> data */ + gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; + /* get a cpu accessible mapping from the pbo */ + if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), pbo_info, info->flags)) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo"); + g_free (pbo_info); + return NULL; + } + info->user_data[0] = pbo_info; + + return pbo_info->data; +} + +static gpointer +_gl_mem_map_cpu_access (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize size) +{ + gpointer data = NULL; + + gst_gl_base_memory_alloc_data ((GstGLBaseMemory *) gl_mem); + + if (!data && gl_mem->pbo + && CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.mem.context)) + data = _pbo_download_transfer (gl_mem, info, size); + + if (!data) { + GstGLMemoryAllocatorClass *alloc_class; + + alloc_class = GST_GL_MEMORY_ALLOCATOR_CLASS (parent_class); + + data = alloc_class->map ((GstGLBaseMemory *) gl_mem, info, size); + } + + return data; +} + +static gpointer +_gl_mem_map_gpu_access (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize size) +{ + gpointer data = &gl_mem->mem.tex_id; + + if ((info->flags & GST_MAP_READ) == GST_MAP_READ) { + if (gl_mem->pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.mem.context)) { + GstMapInfo pbo_info; + + /* data -> pbo */ + if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info, + GST_MAP_READ | GST_MAP_GL)) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo"); + return NULL; + } + + /* pbo -> texture */ + _upload_pbo_memory (gl_mem, info, gl_mem->pbo, &pbo_info); + + gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); + } else { + GstGLMemoryAllocatorClass *alloc_class; + + alloc_class = GST_GL_MEMORY_ALLOCATOR_CLASS (parent_class); + + data = alloc_class->map ((GstGLBaseMemory *) gl_mem, info, size); + } + } + + return data; +} + +static gpointer +_gl_mem_map (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize maxsize) +{ + gpointer data; + + if ((info->flags & GST_MAP_GL) == GST_MAP_GL) { + if (gl_mem->mem.tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) + return &gl_mem->mem.tex_id; + + data = _gl_mem_map_gpu_access (gl_mem, info, maxsize); + } else { /* not GL */ + if (gl_mem->mem.tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot map External OES textures"); + return NULL; + } + + data = _gl_mem_map_cpu_access (gl_mem, info, maxsize); + } + + return data; +} + +static void +_gl_mem_unmap_cpu_access (GstGLMemoryPBO * gl_mem, GstMapInfo * info) +{ + if (!gl_mem->pbo || !CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.mem.context)) + /* PBO's not supported */ + return; + + gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; + gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), + (GstMapInfo *) info->user_data[0]); + g_free (info->user_data[0]); +} + +static void +_gl_mem_unmap (GstGLMemoryPBO * gl_mem, GstMapInfo * info) +{ + if ((info->flags & GST_MAP_GL) == 0) { + _gl_mem_unmap_cpu_access (gl_mem, info); + } +} + +static void +_gl_mem_copy_thread (GstGLContext * context, gpointer data) +{ + const GstGLFuncs *gl; + GstGLMemoryPBOCopyParams *copy_params; + GstGLMemoryPBO *src; + guint tex_id; + guint out_tex_target; + GLuint fboId; + gsize out_width, out_height, out_stride; + GLuint out_gl_format, out_gl_type; + GLuint in_gl_format, in_gl_type; + gsize in_size, out_size; + + copy_params = (GstGLMemoryPBOCopyParams *) data; + src = copy_params->src; + tex_id = copy_params->tex_id; + out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target); + out_width = copy_params->out_width; + out_height = copy_params->out_height; + out_stride = copy_params->out_stride; + + gl = context->gl_vtable; + out_gl_format = gst_gl_format_from_gl_texture_type (copy_params->out_format); + out_gl_type = GL_UNSIGNED_BYTE; + if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + out_gl_type = GL_UNSIGNED_SHORT_5_6_5; + in_gl_format = gst_gl_format_from_gl_texture_type (src->mem.tex_type); + in_gl_type = GL_UNSIGNED_BYTE; + if (src->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + in_gl_type = GL_UNSIGNED_SHORT_5_6_5; + + if (!gl->GenFramebuffers) { + gst_gl_context_set_error (context, + "Context, EXT_framebuffer_object not supported"); + goto error; + } + + in_size = GL_MEM_HEIGHT (src) * GL_MEM_STRIDE (src); + out_size = out_height * out_stride; + + if (copy_params->respecify) { + if (in_size != out_size) { + GST_ERROR ("Cannot copy between textures with backing data of different" + "sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size, + out_size); + goto error; + } + } + + if (!tex_id) { + guint internal_format; + guint out_gl_type; + + out_gl_type = GL_UNSIGNED_BYTE; + if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) + out_gl_type = GL_UNSIGNED_SHORT_5_6_5; + + internal_format = + gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format, + out_gl_type); + + tex_id = + _new_texture (context, out_tex_target, + internal_format, out_gl_format, out_gl_type, copy_params->out_width, + copy_params->out_height); + } + + if (!tex_id) { + GST_WARNING ("Could not create GL texture with context:%p", context); + } + + GST_LOG ("copying memory %p, tex %u into texture %i", + src, src->mem.tex_id, tex_id); + + /* FIXME: try and avoid creating and destroying fbo's every copy... */ + /* create a framebuffer object */ + gl->GenFramebuffers (1, &fboId); + gl->BindFramebuffer (GL_FRAMEBUFFER, fboId); + + gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + gst_gl_texture_target_to_gl (src->mem.tex_target), src->mem.tex_id, 0); + +// if (!gst_gl_context_check_framebuffer_status (src->mem.mem.context)) +// goto fbo_error; + + gl->BindTexture (out_tex_target, tex_id); + if (copy_params->respecify) { + GstMapInfo pbo_info; + + if (!gl->GenBuffers || !src->pbo) { + gst_gl_context_set_error (context, "Cannot reinterpret texture contents " + "without pixel buffer objects"); + gl->BindTexture (out_tex_target, 0); + goto fbo_error; + } + + if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2 + && (in_gl_format != GL_RGBA || in_gl_type != GL_UNSIGNED_BYTE)) { + gst_gl_context_set_error (context, "Cannot copy non RGBA/UNSIGNED_BYTE " + "textures on GLES2"); + gl->BindTexture (out_tex_target, 0); + goto fbo_error; + } + + GST_TRACE ("copying texture data with size of %u*%u*%u", + gst_gl_format_type_n_bytes (in_gl_format, in_gl_type), + src->mem.tex_width, GL_MEM_HEIGHT (src)); + + /* copy tex */ + _read_pixels_to_pbo (src); + + src->pbo->target = GL_PIXEL_UNPACK_BUFFER; + if (!gst_memory_map (GST_MEMORY_CAST (src->pbo), &pbo_info, + GST_MAP_READ | GST_MAP_GL)) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo for reading"); + goto fbo_error; + } + gl->TexSubImage2D (out_tex_target, 0, 0, 0, out_width, out_height, + out_gl_format, out_gl_type, 0); + gst_memory_unmap (GST_MEMORY_CAST (src->pbo), &pbo_info); + } else { /* different sizes */ + gst_gl_memory_copy_teximage (GST_GL_MEMORY_CAST (src), + tex_id, copy_params->tex_target, copy_params->out_format, out_width, + out_height); + } + + gl->BindTexture (out_tex_target, 0); + gl->BindFramebuffer (GL_FRAMEBUFFER, 0); + + gl->DeleteFramebuffers (1, &fboId); + + copy_params->tex_id = tex_id; + copy_params->result = TRUE; + + return; + +/* ERRORS */ +fbo_error: + { + gl->DeleteFramebuffers (1, &fboId); + + copy_params->tex_id = 0; + copy_params->result = FALSE; + return; + } + +error: + { + copy_params->result = FALSE; + return; + } +} + +static GstMemory * +_gl_mem_copy (GstGLMemoryPBO * src, gssize offset, gssize size) +{ + GstAllocationParams params = { 0, GST_MEMORY_CAST (src)->align, 0, 0 }; + GstGLBaseMemoryAllocator *base_mem_allocator; + GstAllocator *allocator; + GstMemory *dest = NULL; + + allocator = GST_MEMORY_CAST (src)->allocator; + base_mem_allocator = (GstGLBaseMemoryAllocator *) allocator; + + if (src->mem.tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { + GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures"); + return NULL; + } + + /* If not doing a full copy, then copy to sysmem, the 2D represention of the + * texture would become wrong */ + if (offset > 0 || size < GST_MEMORY_CAST (src)->size) { + return base_mem_allocator->fallback_mem_copy (GST_MEMORY_CAST (src), offset, + size); + } + + dest = (GstMemory *) _gl_mem_new (allocator, NULL, src->mem.mem.context, + src->mem.tex_target, ¶ms, &src->mem.info, &src->mem.valign, + src->mem.plane, NULL, NULL); + + if (GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) { + if (!gst_gl_base_memory_memcpy ((GstGLBaseMemory *) src, + (GstGLBaseMemory *) dest, offset, size)) { + GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory"); + gst_memory_unref (GST_MEMORY_CAST (dest)); + return NULL; + } + } else { + GstMapInfo dinfo; + + if (!gst_memory_map (GST_MEMORY_CAST (dest), &dinfo, + GST_MAP_WRITE | GST_MAP_GL)) { + GST_CAT_WARNING (GST_CAT_GL_MEMORY, + "Failed not map destination " "for writing"); + gst_memory_unref (GST_MEMORY_CAST (dest)); + return NULL; + } + + if (!gst_gl_memory_copy_into ((GstGLMemory *) src, + ((GstGLMemory *) dest)->tex_id, src->mem.tex_target, + src->mem.tex_type, src->mem.tex_width, GL_MEM_HEIGHT (src))) { + GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory"); + gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo); + gst_memory_unref (GST_MEMORY_CAST (dest)); + return NULL; + } + + gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo); + } + + return dest; +} + +static GstMemory * +_gl_mem_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ + g_warning ("use gst_gl_memory_pbo_alloc () to allocate from this " + "GstGLMemoryPBO allocator"); + + return NULL; +} + +static void +_gl_mem_destroy (GstGLMemoryPBO * gl_mem) +{ + if (gl_mem->pbo) + gst_memory_unref (GST_MEMORY_CAST (gl_mem->pbo)); + gl_mem->pbo = NULL; + + GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class)->destroy ((GstGLBaseMemory + *) gl_mem); +} + +static void +_gl_mem_free (GstAllocator * allocator, GstMemory * mem) +{ + GST_ALLOCATOR_CLASS (parent_class)->free (allocator, mem); +} + +static void +gst_gl_memory_pbo_allocator_class_init (GstGLMemoryPBOAllocatorClass * klass) +{ + GstGLBaseMemoryAllocatorClass *gl_base; + GstGLMemoryAllocatorClass *gl_tex; + GstAllocatorClass *allocator_class; + + gl_tex = (GstGLMemoryAllocatorClass *) klass; + gl_base = (GstGLBaseMemoryAllocatorClass *) klass; + allocator_class = (GstAllocatorClass *) klass; + + gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_mem_create; + gl_tex->map = (GstGLBaseMemoryAllocatorMapFunction) _gl_mem_map; + gl_tex->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _gl_mem_unmap; + gl_tex->copy = (GstGLBaseMemoryAllocatorCopyFunction) _gl_mem_copy; + gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_mem_destroy; + + allocator_class->alloc = _gl_mem_alloc; + allocator_class->free = _gl_mem_free; +} + +static void +gst_gl_memory_pbo_allocator_init (GstGLMemoryPBOAllocator * allocator) +{ + GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); + + alloc->mem_type = GST_GL_MEMORY_PBO_ALLOCATOR_NAME; + + GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +} + +/** + * gst_gl_memory_pbo_copy_into_texture: + * @gl_mem:a #GstGLMemoryPBO + * @tex_id:OpenGL texture id + * @tex_type: a #GstVideoGLTextureType + * @width: width of @tex_id + * @height: height of @tex_id + * @stride: stride of the backing texture data + * @respecify: whether to copy the data or copy per texel + * + * Copies @gl_mem into the texture specfified by @tex_id. The format of @tex_id + * is specified by @tex_type, @width and @height. + * + * If @respecify is %TRUE, then the copy is performed in terms of the texture + * data. This is useful for splitting RGBA textures into RG or R textures or + * vice versa. The requirement for this to succeed is that the backing texture + * data must be the same size, i.e. say a RGBA8 texture is converted into a RG8 + * texture, then the RG texture must have twice as many pixels available for + * output as the RGBA texture. + * + * Otherwise, if @respecify is %FALSE, then the copy is performed per texel + * using glCopyTexImage. See the OpenGL specification for details on the + * mappings between texture formats. + * + * Returns: Whether the copy suceeded + */ +gboolean +gst_gl_memory_pbo_copy_into_texture (GstGLMemoryPBO * gl_mem, guint tex_id, + GstGLTextureTarget target, GstVideoGLTextureType tex_type, gint width, + gint height, gint stride, gboolean respecify) +{ + GstGLMemoryPBOCopyParams copy_params; + + copy_params.src = gl_mem; + copy_params.tex_target = target; + copy_params.tex_id = tex_id; + copy_params.out_format = tex_type; + copy_params.out_width = width; + copy_params.out_height = height; + copy_params.out_stride = stride; + copy_params.respecify = respecify; + + gst_gl_context_thread_add (gl_mem->mem.mem.context, _gl_mem_copy_thread, + ©_params); + + return copy_params.result; +} + +/** + * gst_gl_memory_pbo_wrapped_texture: + * @context: a #GstGLContext + * @texture_id: the GL texture handle + * @texture_target: the GL texture target + * @info: the #GstVideoInfo of the memory + * @plane: The plane this memory will represent + * @user_data: user data + * @notify: Destroy callback for the user data + * + * Wraps a texture handle into a #GstGLMemoryPBO. + * + * Returns: a newly allocated #GstGLMemoryPBO + */ +GstGLMemoryPBO * +gst_gl_memory_pbo_wrapped_texture (GstGLContext * context, + guint texture_id, GstGLTextureTarget target, + GstVideoInfo * info, guint plane, GstVideoAlignment * valign, + gpointer user_data, GDestroyNotify notify) +{ + GstGLMemoryPBO *mem; + + mem = g_slice_new0 (GstGLMemoryPBO); + + mem->mem.tex_id = texture_id; + mem->mem.texture_wrapped = TRUE; + + _gl_mem_init (mem, _gl_allocator, NULL, context, target, NULL, info, valign, + plane, user_data, notify); + + GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD); + + return mem; +} + +/** + * gst_gl_memory_pbo_alloc: + * @context:a #GstGLContext + * @params: a #GstAllocationParams + * @info: the #GstVideoInfo of the memory + * @plane: the plane this memory will represent + * @valign: the #GstVideoAlignment applied to @info + * + * Allocated a new #GstGlMemory. + * + * Returns: a #GstMemory object with a GL texture specified by @vinfo + * from @context + */ +GstMemory * +gst_gl_memory_pbo_alloc (GstGLContext * context, GstGLTextureTarget target, + GstAllocationParams * params, GstVideoInfo * info, guint plane, + GstVideoAlignment * valign) +{ + GstGLMemoryPBO *mem; + + mem = + _gl_mem_new (_gl_allocator, NULL, context, target, params, info, valign, + plane, NULL, NULL); + + return (GstMemory *) mem; +} + +/** + * gst_gl_memory_pbo_wrapped: + * @context:a #GstGLContext + * @info: the #GstVideoInfo of the memory and data + * @plane: the plane this memory will represent + * @valign: the #GstVideoAlignment applied to @info + * @data: the data to wrap + * @user_data: data called with for @notify + * @notify: function called with @user_data when @data needs to be freed + * + * Wrapped @data into a #GstGLMemoryPBO. This version will account for padding + * added to the allocation and expressed through @valign. + * + * Returns: a #GstGLMemoryPBO object with a GL texture specified by @v_info + * from @context and contents specified by @data + */ +GstGLMemoryPBO * +gst_gl_memory_pbo_wrapped (GstGLContext * context, GstGLTextureTarget target, + GstVideoInfo * info, guint plane, GstVideoAlignment * valign, gpointer data, + gpointer user_data, GDestroyNotify notify) +{ + GstGLMemoryPBO *mem; + + mem = _gl_mem_new (_gl_allocator, NULL, context, target, NULL, info, valign, + plane, user_data, notify); + if (!mem) + return NULL; + + mem->pbo->mem.data = data; + + GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD); + if (mem->pbo) + GST_MINI_OBJECT_FLAG_SET (mem->pbo, + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD); + + return mem; +} + +static void +_download_transfer (GstGLContext * context, GstGLMemoryPBO * gl_mem) +{ + GstGLBaseMemory *mem = (GstGLBaseMemory *) gl_mem; + + g_mutex_lock (&mem->lock); + if (_read_pixels_to_pbo (gl_mem)) + GST_CAT_TRACE (GST_CAT_GL_MEMORY, "optimistic download of texture %u " + "using pbo %u", gl_mem->mem.tex_id, gl_mem->pbo->id); + g_mutex_unlock (&mem->lock); +} + +void +gst_gl_memory_pbo_download_transfer (GstGLMemoryPBO * gl_mem) +{ + g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem)); + + gst_gl_context_thread_add (gl_mem->mem.mem.context, + (GstGLContextThreadFunc) _download_transfer, gl_mem); +} + +static void +_upload_transfer (GstGLContext * context, GstGLMemoryPBO * gl_mem) +{ + GstGLBaseMemory *mem = (GstGLBaseMemory *) gl_mem; + GstMapInfo info; + + g_mutex_lock (&mem->lock); + gl_mem->pbo->target = GL_PIXEL_UNPACK_BUFFER; + if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &info, + GST_MAP_READ | GST_MAP_GL)) { + GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Failed to map pbo for reading"); + } else { + gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &info); + } + g_mutex_unlock (&mem->lock); +} + +void +gst_gl_memory_pbo_upload_transfer (GstGLMemoryPBO * gl_mem) +{ + g_return_if_fail (gst_is_gl_memory ((GstMemory *) gl_mem)); + + if (gl_mem->pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.mem.context)) + gst_gl_context_thread_add (gl_mem->mem.mem.context, + (GstGLContextThreadFunc) _upload_transfer, gl_mem); +} + +/** + * gst_gl_memory_pbo_init: + * + * Initializes the GL Memory allocator. It is safe to call this function + * multiple times. This must be called before any other GstGLMemoryPBO operation. + */ +void +gst_gl_memory_pbo_init_once (void) +{ + static volatile gsize _init = 0; + + if (g_once_init_enter (&_init)) { + gst_gl_memory_init_once (); + + GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY, "glmemory", 0, "OpenGL Memory"); + + _gl_allocator = g_object_new (GST_TYPE_GL_MEMORY_PBO_ALLOCATOR, NULL); + + gst_allocator_register (GST_GL_MEMORY_PBO_ALLOCATOR_NAME, + gst_object_ref (_gl_allocator)); + g_once_init_leave (&_init, 1); + } +} + +/** + * gst_is_gl_memory: + * @mem:a #GstMemory + * + * Returns: whether the memory at @mem is a #GstGLMemoryPBO + */ +gboolean +gst_is_gl_memory_pbo (GstMemory * mem) +{ + return mem != NULL && mem->allocator != NULL + && g_type_is_a (G_OBJECT_TYPE (mem->allocator), + GST_TYPE_GL_MEMORY_PBO_ALLOCATOR); +} + +/** + * gst_gl_memory_pbo_setup_buffer: + * @context: a #GstGLContext + * @params: a #GstAllocationParams + * @info: a #GstVideoInfo + * @valign: the #GstVideoAlignment applied to @info + * @buffer: a #GstBuffer + * + * Adds the required #GstGLMemoryPBOs with the correct configuration to + * @buffer based on @info. This version handles padding through @valign. + * + * Returns: whether the memory's were sucessfully added. + */ +gboolean +gst_gl_memory_pbo_setup_buffer (GstGLContext * context, + GstGLTextureTarget target, GstAllocationParams * params, + GstVideoInfo * info, GstVideoAlignment * valign, GstBuffer * buffer) +{ + GstGLMemoryPBO *gl_mem[GST_VIDEO_MAX_PLANES] = { NULL, }; + guint n_mem, i, v, views; + + n_mem = GST_VIDEO_INFO_N_PLANES (info); + + if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) == + GST_VIDEO_MULTIVIEW_MODE_SEPARATED) + views = info->views; + else + views = 1; + + for (v = 0; v < views; v++) { + for (i = 0; i < n_mem; i++) { + gl_mem[i] = + (GstGLMemoryPBO *) gst_gl_memory_pbo_alloc (context, target, params, + info, i, valign); + if (gl_mem[i] == NULL) + return FALSE; + + gst_buffer_append_memory (buffer, (GstMemory *) gl_mem[i]); + } + + gst_buffer_add_video_meta_full (buffer, v, + GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info), + GST_VIDEO_INFO_HEIGHT (info), n_mem, info->offset, info->stride); + } + + return TRUE; +} + +/** + * gst_gl_memory_pbo_setup_wrapped: + * @context: a #GstGLContext + * @info: a #GstVideoInfo + * @valign: a #GstVideoInfo + * @data: a list of per plane data pointers + * @textures: (transfer out): a list of #GstGLMemoryPBO + * @user_data: user data for the destroy function + * @notify: A function called each time a memory is freed + * + * Wraps per plane data pointer in @data into the corresponding entry in + * @textures based on @info and padding from @valign. Note that the @notify + * will be called as many time as there is planes. + * + * Returns: whether the memory's were sucessfully created. + */ +gboolean +gst_gl_memory_pbo_setup_wrapped (GstGLContext * context, + GstGLTextureTarget target, GstVideoInfo * info, GstVideoAlignment * valign, + gpointer data[GST_VIDEO_MAX_PLANES], + GstGLMemoryPBO * textures[GST_VIDEO_MAX_PLANES], gpointer user_data, + GDestroyNotify notify) +{ + gint i; + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) { + textures[i] = + (GstGLMemoryPBO *) gst_gl_memory_pbo_wrapped (context, target, info, i, + valign, data[i], user_data, notify); + } + + return TRUE; +} diff --git a/gst-libs/gst/gl/gstglmemorypbo.h b/gst-libs/gst/gl/gstglmemorypbo.h new file mode 100644 index 0000000000..335354a495 --- /dev/null +++ b/gst-libs/gst/gl/gstglmemorypbo.h @@ -0,0 +1,139 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2015 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_GL_MEMORY_PBO_H_ +#define _GST_GL_MEMORY_PBO_H_ + +#include +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_GL_MEMORY_PBO_ALLOCATOR (gst_gl_memory_pbo_allocator_get_type()) +GType gst_gl_memory_pbo_allocator_get_type(void); + +#define GST_IS_GL_MEMORY_PBO_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_MEMORY_PBO_ALLOCATOR)) +#define GST_IS_GL_MEMORY_PBO_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_MEMORY_PBO_ALLOCATOR)) +#define GST_GL_MEMORY_PBO_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_MEMORY_PBO_ALLOCATOR, GstGLMemoryPBOAllocatorClass)) +#define GST_GL_MEMORY_PBO_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_MEMORY_PBO_ALLOCATOR, GstGLMemoryPBOAllocator)) +#define GST_GL_MEMORY_PBO_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_MEMORY_PBO_ALLOCATOR, GstGLAllocatorClass)) +#define GST_GL_MEMORY_PBO_ALLOCATOR_CAST(obj) ((GstGLMemoryPBOAllocator *)(obj)) + +/** + * GstGLMemoryPBO: + * + * Private instance + */ +struct _GstGLMemoryPBO +{ + GstGLMemory mem; + + /* */ + GstGLBuffer *pbo; +}; + +/** + * GST_GL_MEMORY_PBO_ALLOCATOR: + * + * The name of the GL Memory PBO allocator + */ +#define GST_GL_MEMORY_PBO_ALLOCATOR_NAME "GLMemoryPBO" + +void gst_gl_memory_pbo_init_once (void); +gboolean gst_is_gl_memory_pbo (GstMemory * mem); + +GstMemory * gst_gl_memory_pbo_alloc (GstGLContext * context, + GstGLTextureTarget target, + GstAllocationParams *params, + GstVideoInfo * info, + guint plane, + GstVideoAlignment *valign); +GstGLMemoryPBO * gst_gl_memory_pbo_wrapped (GstGLContext * context, + GstGLTextureTarget target, + GstVideoInfo * info, + guint plane, + GstVideoAlignment *valign, + gpointer data, + gpointer user_data, + GDestroyNotify notify); +GstGLMemoryPBO * gst_gl_memory_pbo_wrapped_texture (GstGLContext * context, + guint texture_id, + GstGLTextureTarget target, + GstVideoInfo * info, + guint plane, + GstVideoAlignment *valign, + gpointer user_data, + GDestroyNotify notify); + +void gst_gl_memory_pbo_download_transfer (GstGLMemoryPBO * gl_mem); +void gst_gl_memory_pbo_upload_transfer (GstGLMemoryPBO * gl_mem); + +gboolean gst_gl_memory_pbo_copy_into_texture (GstGLMemoryPBO *gl_mem, + guint tex_id, + GstGLTextureTarget target, + GstVideoGLTextureType tex_type, + gint width, + gint height, + gint stride, + gboolean respecify); + +gboolean gst_gl_memory_pbo_setup_buffer (GstGLContext * context, + GstGLTextureTarget target, + GstAllocationParams * params, + GstVideoInfo * info, + GstVideoAlignment *valign, + GstBuffer * buffer); +gboolean gst_gl_memory_pbo_setup_wrapped (GstGLContext * context, + GstGLTextureTarget target, + GstVideoInfo * info, + GstVideoAlignment *valign, + gpointer data[GST_VIDEO_MAX_PLANES], + GstGLMemoryPBO *textures[GST_VIDEO_MAX_PLANES], + gpointer user_data, + GDestroyNotify notify); + +/** + * GstGLAllocator + * + * Opaque #GstGLAllocator struct + */ +struct _GstGLMemoryPBOAllocator +{ + GstGLMemoryAllocator parent; +}; + +/** + * GstGLAllocatorClass: + * + * The #GstGLAllocatorClass only contains private data + */ +struct _GstGLMemoryPBOAllocatorClass +{ + GstGLMemoryAllocatorClass parent_class; +}; + +G_END_DECLS + +#endif /* _GST_GL_MEMORY_PBO_H_ */ diff --git a/gst-libs/gst/gl/gstgloverlaycompositor.c b/gst-libs/gst/gl/gstgloverlaycompositor.c index a3f906d1fe..b62e396ef3 100644 --- a/gst-libs/gst/gl/gstgloverlaycompositor.c +++ b/gst-libs/gst/gl/gstgloverlaycompositor.c @@ -347,9 +347,9 @@ gst_gl_composition_overlay_upload (GstGLCompositionOverlay * overlay, gst_gl_composition_overlay_add_transformation (overlay, buf); comp_gl_memory = - gst_gl_memory_wrapped (overlay->context, GST_GL_TEXTURE_TARGET_2D, - &comp_frame->info, 0, NULL, comp_frame->data[0], comp_frame, - _video_frame_unmap_and_free); + (GstGLMemory *) gst_gl_memory_pbo_wrapped (overlay->context, + GST_GL_TEXTURE_TARGET_2D, &comp_frame->info, 0, NULL, + comp_frame->data[0], comp_frame, _video_frame_unmap_and_free); overlay_buffer = gst_buffer_new (); gst_buffer_append_memory (overlay_buffer, (GstMemory *) comp_gl_memory); diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c index ed5c09178f..51ac1ba79c 100644 --- a/gst-libs/gst/gl/gstglupload.c +++ b/gst-libs/gst/gl/gstglupload.c @@ -223,7 +223,7 @@ _gl_memory_upload_propose_allocation (gpointer impl, GstQuery * decide_query, GstAllocationParams params; gst_allocation_params_init (¶ms); - allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); + allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME); gst_query_add_allocation_param (query, allocator, ¶ms); gst_object_unref (allocator); } @@ -308,7 +308,8 @@ _gl_memory_upload_perform (gpointer impl, GstBuffer * buffer, gl_mem->mem.context)) return GST_GL_UPLOAD_UNSHARED_GL_CONTEXT; - gst_gl_memory_upload_transfer (gl_mem); + if (gst_is_gl_memory_pbo (mem)) + gst_gl_memory_pbo_upload_transfer ((GstGLMemoryPBO *) mem); } *outbuf = gst_buffer_ref (buffer); @@ -460,8 +461,9 @@ _egl_image_upload_perform_gl_thread (GstGLContext * context, /* FIXME: buffer pool */ *image->outbuf = gst_buffer_new (); - gst_gl_memory_setup_buffer (image->upload->context, GST_GL_TEXTURE_TARGET_2D, - NULL, &image->upload->priv->out_info, NULL, *image->outbuf); + gst_gl_memory_pbo_setup_buffer (image->upload->context, + GST_GL_TEXTURE_TARGET_2D, NULL, &image->upload->priv->out_info, NULL, + *image->outbuf); n = gst_buffer_n_memory (image->buffer); for (i = 0; i < n; i++) { @@ -479,8 +481,8 @@ _egl_image_upload_perform_gl_thread (GstGLContext * context, } if (GST_IS_GL_BUFFER_POOL (image->buffer->pool)) - gst_gl_buffer_pool_replace_last_buffer (GST_GL_BUFFER_POOL (image->buffer-> - pool), image->buffer); + gst_gl_buffer_pool_replace_last_buffer (GST_GL_BUFFER_POOL (image-> + buffer->pool), image->buffer); } static GstGLUploadReturn @@ -621,11 +623,11 @@ _upload_meta_upload_propose_allocation (gpointer impl, GstQuery * decide_query, gpointer handle; gl_apis = - gst_gl_api_to_string (gst_gl_context_get_gl_api (upload-> - upload->context)); + gst_gl_api_to_string (gst_gl_context_get_gl_api (upload->upload-> + context)); platform = - gst_gl_platform_to_string (gst_gl_context_get_gl_platform - (upload->upload->context)); + gst_gl_platform_to_string (gst_gl_context_get_gl_platform (upload-> + upload->context)); handle = (gpointer) gst_gl_context_get_gl_context (upload->upload->context); gl_context = @@ -677,8 +679,9 @@ _upload_meta_upload_perform (gpointer impl, GstBuffer * buffer, /* FIXME: buffer pool */ *outbuf = gst_buffer_new (); - gst_gl_memory_setup_buffer (upload->upload->context, GST_GL_TEXTURE_TARGET_2D, - NULL, &upload->upload->priv->in_info, NULL, *outbuf); + gst_gl_memory_pbo_setup_buffer (upload->upload->context, + GST_GL_TEXTURE_TARGET_2D, NULL, &upload->upload->priv->in_info, NULL, + *outbuf); for (i = 0; i < GST_GL_UPLOAD_MAX_PLANES; i++) { guint tex_id = 0; @@ -872,9 +875,10 @@ _raw_data_upload_perform (gpointer impl, GstBuffer * buffer, GST_VIDEO_MULTIVIEW_MODE_SEPARATED) max_planes *= GST_VIDEO_INFO_VIEWS (in_info); - gst_gl_memory_setup_wrapped (raw->upload->context, GST_GL_TEXTURE_TARGET_2D, - &raw->upload->priv->in_info, NULL, raw->in_frame->frame.data, in_tex, - raw->in_frame, (GDestroyNotify) _raw_upload_frame_unref); + gst_gl_memory_pbo_setup_wrapped (raw->upload->context, + GST_GL_TEXTURE_TARGET_2D, &raw->upload->priv->in_info, NULL, + raw->in_frame->frame.data, (GstGLMemoryPBO **) in_tex, raw->in_frame, + (GDestroyNotify) _raw_upload_frame_unref); /* FIXME Use a buffer pool to cache the generated textures */ *outbuf = gst_buffer_new (); diff --git a/gst-libs/gst/gl/gstglviewconvert.c b/gst-libs/gst/gl/gstglviewconvert.c index 322ffd6563..3f36b408c6 100644 --- a/gst-libs/gst/gl/gstglviewconvert.c +++ b/gst-libs/gst/gl/gstglviewconvert.c @@ -1892,7 +1892,7 @@ static gboolean _gen_buffer (GstGLViewConvert * viewconvert, GstBuffer ** target) { *target = gst_buffer_new (); - if (!gst_gl_memory_setup_buffer (viewconvert->context, + if (!gst_gl_memory_pbo_setup_buffer (viewconvert->context, viewconvert->to_texture_target, NULL, &viewconvert->out_info, NULL, *target)) { return FALSE; @@ -2017,7 +2017,7 @@ _do_view_convert (GstGLContext * context, GstGLViewConvert * viewconvert) * the attachments i.e. the smallest attachment size */ if (!priv->out_tex[j]) priv->out_tex[j] = - (GstGLMemory *) gst_gl_memory_alloc (context, + (GstGLMemory *) gst_gl_memory_pbo_alloc (context, viewconvert->to_texture_target, NULL, &temp_info, 0, NULL); } else { priv->out_tex[j] = out_tex; @@ -2069,10 +2069,8 @@ out: res = FALSE; continue; } - gst_gl_memory_copy_into_texture (priv->out_tex[j], - out_tex->tex_id, viewconvert->to_texture_target, out_tex->tex_type, - width, height, - GST_VIDEO_INFO_PLANE_STRIDE (&out_tex->info, out_tex->plane), FALSE); + gst_gl_memory_copy_into (priv->out_tex[j], out_tex->tex_id, + viewconvert->to_texture_target, out_tex->tex_type, width, height); gst_memory_unmap ((GstMemory *) out_tex, &to_info); } diff --git a/tests/check/libs/gstglmemory.c b/tests/check/libs/gstglmemory.c index 68ea7bc171..11903fa37a 100644 --- a/tests/check/libs/gstglmemory.c +++ b/tests/check/libs/gstglmemory.c @@ -39,7 +39,7 @@ setup (void) display = gst_gl_display_new (); context = gst_gl_context_new (display); gst_gl_context_create (context, 0, NULL); - gst_gl_memory_init (); + gst_gl_memory_init_once (); } static void @@ -60,7 +60,7 @@ GST_START_TEST (test_basic) GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420 }; - gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); + gl_allocator = gst_allocator_find (GST_GL_MEMORY_PBO_ALLOCATOR_NAME); fail_if (gl_allocator == NULL); /* test allocator creation */ @@ -74,8 +74,8 @@ GST_START_TEST (test_basic) for (j = 0; j < GST_VIDEO_INFO_N_PLANES (&v_info); j++) { mem = - gst_gl_memory_alloc (context, GST_GL_TEXTURE_TARGET_2D, NULL, &v_info, - j, NULL); + gst_gl_memory_pbo_alloc (context, GST_GL_TEXTURE_TARGET_2D, NULL, + &v_info, j, NULL); fail_if (mem == NULL); gl_mem = (GstGLMemory *) mem; @@ -120,47 +120,47 @@ GST_START_TEST (test_transfer) GstMemory *mem, *mem2, *mem3; GstMapInfo map_info; - gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); + gl_allocator = gst_allocator_find (GST_GL_MEMORY_PBO_ALLOCATOR_NAME); fail_if (gl_allocator == NULL); gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, 1, 1); /* texture creation */ mem = - (GstMemory *) gst_gl_memory_alloc (context, GST_GL_TEXTURE_TARGET_2D, + (GstMemory *) gst_gl_memory_pbo_alloc (context, GST_GL_TEXTURE_TARGET_2D, NULL, &v_info, 0, NULL); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test wrapping raw data */ mem2 = - (GstMemory *) gst_gl_memory_wrapped (context, GST_GL_TEXTURE_TARGET_2D, - &v_info, 0, NULL, rgba_pixel, NULL, NULL); + (GstMemory *) gst_gl_memory_pbo_wrapped (context, + GST_GL_TEXTURE_TARGET_2D, &v_info, 0, NULL, rgba_pixel, NULL, NULL); fail_if (mem == NULL); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* wrapped texture creation */ - mem3 = (GstMemory *) gst_gl_memory_wrapped_texture (context, + mem3 = (GstMemory *) gst_gl_memory_pbo_wrapped_texture (context, ((GstGLMemory *) mem)->tex_id, GST_GL_TEXTURE_TARGET_2D, &v_info, 0, NULL, NULL, NULL); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* check data/flags are correct */ fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (((gchar *) map_info.data)[0] == rgba_pixel[0]); fail_unless (((gchar *) map_info.data)[1] == rgba_pixel[1]); @@ -170,32 +170,31 @@ GST_START_TEST (test_transfer) gst_memory_unmap (mem2, &map_info); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ | GST_MAP_GL)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test texture copy */ - fail_unless (gst_gl_memory_copy_into_texture ((GstGLMemory *) mem2, + fail_unless (gst_gl_memory_copy_into ((GstGLMemory *) mem2, ((GstGLMemory *) mem)->tex_id, GST_GL_TEXTURE_TARGET_2D, - GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 1, 1, 4, FALSE)); - GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD); - GST_GL_MEMORY_ADD_TRANSFER (mem, GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD); + GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 1, 1)); + GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); gst_memory_unmap (mem2, &map_info); @@ -213,9 +212,9 @@ GST_START_TEST (test_transfer) fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_READ)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (((gchar *) map_info.data)[0] == rgba_pixel[0]); fail_unless (((gchar *) map_info.data)[1] == rgba_pixel[1]); @@ -229,18 +228,18 @@ GST_START_TEST (test_transfer) gst_memory_unmap (mem3, &map_info); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test download flag */ fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_WRITE | GST_MAP_GL)); gst_memory_unmap (mem3, &map_info); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); if (gst_gl_context_get_error ()) printf ("%s\n", gst_gl_context_get_error ()); @@ -261,22 +260,22 @@ GST_START_TEST (test_separate_transfer) GstMemory *mem; GstMapInfo info; - gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); + gl_allocator = gst_allocator_find (GST_GL_MEMORY_PBO_ALLOCATOR_NAME); fail_if (gl_allocator == NULL); gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, 1, 1); mem = - (GstMemory *) gst_gl_memory_wrapped (context, GST_GL_TEXTURE_TARGET_2D, - &v_info, 0, NULL, rgba_pixel, NULL, NULL); + (GstMemory *) gst_gl_memory_pbo_wrapped (context, + GST_GL_TEXTURE_TARGET_2D, &v_info, 0, NULL, rgba_pixel, NULL, NULL); fail_if (mem == NULL); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); - gst_gl_memory_upload_transfer ((GstGLMemory *) mem); + gst_gl_memory_pbo_upload_transfer ((GstGLMemoryPBO *) mem); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, - GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)); + GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (gst_memory_map (mem, &info, GST_MAP_READ));