diff options
author | Matthew Waters <matthew@centricular.com> | 2015-12-14 13:08:10 +1100 |
---|---|---|
committer | Matthew Waters <matthew@centricular.com> | 2015-12-14 16:34:54 +1100 |
commit | 6cf8da132b6eb75084871ac4409356be62537b2f (patch) | |
tree | 5d0dfc8cf55ef71c11cfc5e9c0d0dd5d5ccab9d1 | |
parent | 27e724df8f0b7bb0d98a6c1589777633b3dadcba (diff) | |
download | gstreamer-plugins-bad-6cf8da132b6eb75084871ac4409356be62537b2f.tar.gz |
gl: add a GL buffer based GstMemory
Heavily based on GstGLBaseBuffer that is a subclass of GstGLBaseMemory.
Provides GPU and CPU accessible GL buffer objects by GL handle or by
sysmem data pointer.
-rw-r--r-- | docs/libs/gst-plugins-bad-libs.types | 2 | ||||
-rw-r--r-- | gst-libs/gst/gl/Makefile.am | 2 | ||||
-rw-r--r-- | gst-libs/gst/gl/gl.h | 1 | ||||
-rw-r--r-- | gst-libs/gst/gl/gstgl_fwd.h | 4 | ||||
-rw-r--r-- | gst-libs/gst/gl/gstglbuffer.c | 379 | ||||
-rw-r--r-- | gst-libs/gst/gl/gstglbuffer.h | 118 | ||||
-rw-r--r-- | gst-libs/gst/gl/gstgldisplay.c | 1 |
7 files changed, 506 insertions, 1 deletions
diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types index f74626c75..83eebef20 100644 --- a/docs/libs/gst-plugins-bad-libs.types +++ b/docs/libs/gst-plugins-bad-libs.types @@ -26,7 +26,7 @@ gst_mpegts_stream_type_get_type gst_insert_bin_get_type -gst_gl_allocator_get_type +gst_gl_buffer_allocator_get_type gst_gl_base_filter_get_type gst_gl_buffer_pool_get_type gst_gl_color_convert_get_type diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 04b0ec6a0..bc83ce387 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -14,6 +14,7 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \ gstgldebug.c \ gstglbasebuffer.c \ gstglbasememory.c \ + gstglbuffer.c \ gstglmemory.c \ gstglbufferpool.c \ gstglfilter.c \ @@ -43,6 +44,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gstgldebug.h \ gstglbasebuffer.h \ gstglbasememory.h \ + gstglbuffer.h \ gstglmemory.h \ gstglbufferpool.h \ gstglfilter.h \ diff --git a/gst-libs/gst/gl/gl.h b/gst-libs/gst/gl/gl.h index d8d40d6d4..44dbbecf5 100644 --- a/gst-libs/gst/gl/gl.h +++ b/gst-libs/gst/gl/gl.h @@ -42,6 +42,7 @@ #include <gst/gl/gstglupload.h> #include <gst/gl/gstglbasebuffer.h> #include <gst/gl/gstglbasememory.h> +#include <gst/gl/gstglbuffer.h> #include <gst/gl/gstglmemory.h> #include <gst/gl/gstglbufferpool.h> #include <gst/gl/gstglframebuffer.h> diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h index e532aa4f4..0f45d0ee1 100644 --- a/gst-libs/gst/gl/gstgl_fwd.h +++ b/gst-libs/gst/gl/gstgl_fwd.h @@ -47,6 +47,10 @@ typedef struct _GstGLBaseMemory GstGLBaseMemory; typedef struct _GstGLBaseMemoryAllocator GstGLBaseMemoryAllocator; typedef struct _GstGLBaseMemoryAllocatorClass GstGLBaseMemoryAllocatorClass; +typedef struct _GstGLBuffer GstGLBuffer; +typedef struct _GstGLBufferAllocator GstGLBufferAllocator; +typedef struct _GstGLBufferAllocatorClass GstGLBufferAllocatorClass; + typedef struct _GstGLMemory GstGLMemory; typedef struct _GstGLAllocator GstGLAllocator; typedef struct _GstGLAllocatorClass GstGLAllocatorClass; diff --git a/gst-libs/gst/gl/gstglbuffer.c b/gst-libs/gst/gl/gstglbuffer.c new file mode 100644 index 000000000..f7b244b0e --- /dev/null +++ b/gst-libs/gst/gl/gstglbuffer.c @@ -0,0 +1,379 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> + * + * 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 <string.h> + +#include "gstglbuffer.h" +#include "gstglutils.h" + +/** + * SECTION:gstglbuffer + * @short_description: memory subclass for GL buffers + * @see_also: #GstMemory, #GstAllocator + * + * GstGLBuffer is a #GstMemory subclass providing support for the mapping of + * GL buffers. + * + * Data is uploaded or downloaded from the GPU as is necessary. + */ + +/* Implementation notes: + * + * Currently does not take into account GLES2 differences (no mapbuffer) + */ + +#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)) + +/* compatibility definitions... */ +#ifndef GL_MAP_READ_BIT +#define GL_MAP_READ_BIT 0x0001 +#endif +#ifndef GL_MAP_WRITE_BIT +#define GL_MAP_WRITE_BIT 0x0002 +#endif +#ifndef GL_COPY_READ_BUFFER +#define GL_COPY_READ_BUFFER 0x8F36 +#endif +#ifndef GL_COPY_WRITE_BUFFER +#define GL_COPY_WRITE_BUFFER 0x8F37 +#endif + +GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_BUFFER); +#define GST_CAT_DEFUALT GST_CAT_GL_BUFFER + +static GstAllocator *_gl_buffer_allocator; + +static gboolean +_gl_buffer_create (GstGLBuffer * gl_mem, GError ** error) +{ + const GstGLFuncs *gl = gl_mem->mem.context->gl_vtable; + + gl->GenBuffers (1, &gl_mem->id); + gl->BindBuffer (gl_mem->target, gl_mem->id); + gl->BufferData (gl_mem->target, gl_mem->mem.mem.maxsize, NULL, + gl_mem->usage_hints); + gl->BindBuffer (gl_mem->target, 0); + + return TRUE; +} + +struct create_data +{ + GstGLBuffer *mem; + gboolean result; +}; + +static void +_gl_buffer_init (GstGLBuffer * mem, GstAllocator * allocator, + GstMemory * parent, GstGLContext * context, guint gl_target, guint gl_usage, + GstAllocationParams * params, gsize size) +{ + mem->target = gl_target; + mem->usage_hints = gl_usage; + + gst_gl_base_memory_init ((GstGLBaseMemory *) mem, allocator, parent, context, + params, size, NULL, NULL); + + GST_CAT_DEBUG (GST_CAT_GL_BUFFER, "new GL buffer memory:%p size:%" + G_GSIZE_FORMAT, mem, mem->mem.mem.maxsize); +} + +static GstGLBuffer * +_gl_buffer_new (GstAllocator * allocator, GstMemory * parent, + GstGLContext * context, guint gl_target, guint gl_usage, + GstAllocationParams * params, gsize size) +{ + GstGLBuffer *ret = g_new0 (GstGLBuffer, 1); + _gl_buffer_init (ret, allocator, parent, context, gl_target, gl_usage, + params, size); + + return ret; +} + +static gpointer +gst_gl_buffer_cpu_access (GstGLBuffer * mem, GstMapInfo * info, gsize size) +{ + const GstGLFuncs *gl = mem->mem.context->gl_vtable; + gpointer data, ret; + + if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (mem))) + return NULL; + + ret = mem->mem.data; + + GST_CAT_LOG (GST_CAT_GL_BUFFER, "mapping id %d size %" G_GSIZE_FORMAT, + mem->id, size); + + /* The extra data pointer indirection/memcpy is needed for coherent across + * concurrent map()'s in both GL and CPU */ + if (GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BUFFER_FLAG_NEED_DOWNLOAD) + && (info->flags & GST_MAP_GL) == 0 && (info->flags & GST_MAP_READ) != 0) { + gl->BindBuffer (mem->target, mem->id); + + if (gl->MapBufferRange) { + /* FIXME: optionally remove this with a flag and return the + * glMapBufferRange pointer (requires + * GL_ARB_buffer_storage/GL4/GL_COHERENT_BIT) */ + guint gl_map_flags = GL_MAP_READ_BIT; + + data = gl->MapBufferRange (mem->target, 0, size, gl_map_flags); + + if (data) + memcpy (mem->mem.data, data, size); + + gl->UnmapBuffer (mem->target); + ret = mem->mem.data; + } else if (gl->GetBufferSubData) { + gl->GetBufferSubData (mem->target, 0, size, mem->mem.data); + ret = mem->mem.data; + } else { + ret = NULL; + } + gl->BindBuffer (mem->target, 0); + } + + return ret; +} + +static void +gst_gl_buffer_upload_cpu_write (GstGLBuffer * mem, GstMapInfo * info, + gsize size) +{ + const GstGLFuncs *gl = mem->mem.context->gl_vtable; + gpointer data; + + if (!mem->mem.data) + /* no data pointer has been written */ + return; + + /* The extra data pointer indirection/memcpy is needed for coherent across + * concurrent map()'s in both GL and CPU */ + /* FIXME: uploading potentially half-written data for libav pushing READWRITE + * mapped buffers */ + if (GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BUFFER_FLAG_NEED_UPLOAD) + || (mem->mem.map_flags & GST_MAP_WRITE) != 0) { + gl->BindBuffer (mem->target, mem->id); + + if (gl->MapBufferRange) { + /* FIXME: optionally remove this with a flag and return the + * glMapBufferRange pointer (requires + * GL_ARB_buffer_storage/GL4/GL_COHERENT_BIT) */ + guint gl_map_flags = GL_MAP_WRITE_BIT; + + data = gl->MapBufferRange (mem->target, 0, size, gl_map_flags); + + if (data) + memcpy (data, mem->mem.data, size); + + gl->UnmapBuffer (mem->target); + } else if (gl->BufferSubData) { + gl->BufferSubData (mem->target, 0, size, mem->mem.data); + } + gl->BindBuffer (mem->target, 0); + } +} + +static gpointer +_gl_buffer_map (GstGLBuffer * mem, GstMapInfo * info, gsize size) +{ + if ((info->flags & GST_MAP_GL) != 0) { + if (info->flags & GST_MAP_READ) { + gst_gl_buffer_upload_cpu_write (mem, info, size); + } + return &mem->id; + } else { + return gst_gl_buffer_cpu_access (mem, info, size); + } + + return NULL; +} + +static void +_gl_buffer_unmap (GstGLBuffer * mem, GstMapInfo * info) +{ + /* XXX: optimistically transfer data */ +} + +static gboolean +gst_gl_buffer_copy_buffer_sub_data (GstGLBuffer * src, + GstGLBuffer * dest, gssize offset, gssize size) +{ + const GstGLFuncs *gl = src->mem.context->gl_vtable; + GstMapInfo sinfo, dinfo; + + if (!gl->CopyBufferSubData) + /* This is GL(ES) 3.0+ only */ + return FALSE; + + if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ | GST_MAP_GL)) { + GST_CAT_WARNING (GST_CAT_GL_BUFFER, + "failed to read map source memory %p", src); + return FALSE; + } + + if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE | GST_MAP_GL)) { + GST_CAT_WARNING (GST_CAT_GL_BUFFER, + "failed to write map destination memory %p", dest); + gst_memory_unmap ((GstMemory *) src, &sinfo); + return FALSE; + } + + gl->BindBuffer (GL_COPY_READ_BUFFER, src->id); + gl->BindBuffer (GL_COPY_WRITE_BUFFER, dest->id); + gl->CopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, + offset, 0, size); + + gst_memory_unmap ((GstMemory *) src, &sinfo); + gst_memory_unmap ((GstMemory *) dest, &dinfo); + + return TRUE; +} + +static GstGLBuffer * +_gl_buffer_copy (GstGLBuffer * src, gssize offset, gssize size) +{ + GstAllocator *allocator = src->mem.mem.allocator; + GstAllocationParams params = { 0, src->mem.mem.align, 0, 0 }; + GstGLBuffer *dest = NULL; + + dest = _gl_buffer_new (allocator, NULL, src->mem.context, + src->target, src->usage_hints, ¶ms, src->mem.mem.maxsize); + + /* If not doing a full copy, then copy to sysmem, the 2D represention of the + * texture would become wrong */ + if (GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) { + if (!gst_gl_base_memory_memcpy (GST_GL_BASE_MEMORY_CAST (src), + GST_GL_BASE_MEMORY_CAST (dest), offset, size)) { + GST_CAT_WARNING (GST_CAT_GL_BUFFER, "Could not copy GL Buffer"); + gst_memory_unref (GST_MEMORY_CAST (dest)); + dest = NULL; + } + } else { + if (!gst_gl_buffer_copy_buffer_sub_data (src, dest, offset, size)) { + if (!gst_gl_base_memory_memcpy (GST_GL_BASE_MEMORY_CAST (src), + GST_GL_BASE_MEMORY_CAST (dest), offset, size)) { + GST_CAT_WARNING (GST_CAT_GL_BUFFER, "Could not copy GL Buffer"); + gst_memory_unref (GST_MEMORY_CAST (dest)); + dest = NULL; + } + } + } + + return dest; +} + +static GstMemory * +_gl_buffer_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ + g_critical ("Need to use gst_gl_buffer_alloc() to allocate from " + "this allocator"); + + return NULL; +} + +static void +_gl_buffer_destroy (GstGLBuffer * mem) +{ + const GstGLFuncs *gl = mem->mem.context->gl_vtable; + + gl->DeleteBuffers (1, &mem->id); +} + +G_DEFINE_TYPE (GstGLBufferAllocator, gst_gl_buffer_allocator, + GST_TYPE_GL_BASE_MEMORY_ALLOCATOR); + +static void +gst_gl_buffer_allocator_class_init (GstGLBufferAllocatorClass * klass) +{ + GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass; + GstGLBaseMemoryAllocatorClass *gl_base; + + gl_base = (GstGLBaseMemoryAllocatorClass *) klass; + + gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_buffer_create; + gl_base->map = (GstGLBaseMemoryAllocatorMapFunction) _gl_buffer_map; + gl_base->unmap = (GstGLBaseMemoryAllocatorUnmapFunction) _gl_buffer_unmap; + gl_base->copy = (GstGLBaseMemoryAllocatorCopyFunction) _gl_buffer_copy; + gl_base->destroy = + (GstGLBaseMemoryAllocatorDestroyFunction) _gl_buffer_destroy; + + allocator_class->alloc = _gl_buffer_alloc; +} + +static void +gst_gl_buffer_allocator_init (GstGLBufferAllocator * allocator) +{ +} + +/** + * gst_gl_buffer_init_once: + * + * Initializes the GL Buffer allocator. It is safe to call this function + * multiple times. This must be called before any other GstGLBuffer operation. + */ +void +gst_gl_buffer_init_once (void) +{ + static volatile gsize _init = 0; + + if (g_once_init_enter (&_init)) { + gst_gl_base_memory_init_once (); + + GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_BUFFER, "glbuffer", 0, "OpenGL Buffer"); + + _gl_buffer_allocator = + g_object_new (gst_gl_buffer_allocator_get_type (), NULL); + + gst_allocator_register (GST_GL_BUFFER_ALLOCATOR_NAME, + gst_object_ref (_gl_buffer_allocator)); + g_once_init_leave (&_init, 1); + } +} + +/** + * gst_is_gl_buffer: + * @mem:a #GstMemory + * + * Returns: whether the memory at @mem is a #GstGLBuffer + */ +gboolean +gst_is_gl_buffer (GstMemory * mem) +{ + return mem != NULL && mem->allocator != NULL && + g_type_is_a (G_OBJECT_TYPE (mem->allocator), + GST_TYPE_GL_BUFFER_ALLOCATOR); +} + +GstGLBuffer * +gst_gl_buffer_alloc (GstGLContext * context, guint gl_target, guint gl_usage, + GstAllocationParams * params, gsize maxsize) +{ + return _gl_buffer_new (_gl_buffer_allocator, NULL, context, gl_target, + gl_usage, params, maxsize); +} diff --git a/gst-libs/gst/gl/gstglbuffer.h b/gst-libs/gst/gl/gstglbuffer.h new file mode 100644 index 000000000..a88a73b88 --- /dev/null +++ b/gst-libs/gst/gl/gstglbuffer.h @@ -0,0 +1,118 @@ +/* + * GStreamer + * Copyright (C) 2015 Matthew Waters <matthew@centricular.com> + * + * 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_BUFFER_H_ +#define _GST_GL_BUFFER_H_ + +#include <gst/gst.h> +#include <gst/gstallocator.h> +#include <gst/gstmemory.h> + +#include <gst/gl/gstglbasememory.h> + +G_BEGIN_DECLS + +#define GST_TYPE_GL_BUFFER_ALLOCATOR (gst_gl_buffer_allocator_get_type()) +GType gst_gl_buffer_allocator_get_type(void); + +#define GST_IS_GL_BUFFER_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_ALLOCATOR)) +#define GST_IS_GL_BUFFER_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_BUFFER_ALLOCATOR)) +#define GST_GL_BUFFER_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_BUFFER_ALLOCATOR, GstGLBufferAllocatorClass)) +#define GST_GL_BUFFER_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_BUFFER_ALLOCATOR, GstGLBufferAllocator)) +#define GST_GL_BUFFER_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_BUFFER_ALLOCATOR, GstGLBufferAllocatorClass)) +#define GST_GL_BUFFER_ALLOCATOR_CAST(obj) ((GstGLBufferAllocator *)(obj)) + + +typedef enum +{ + GST_GL_BUFFER_FLAG_NEED_DOWNLOAD = (GST_MEMORY_FLAG_LAST << 0), + GST_GL_BUFFER_FLAG_NEED_UPLOAD = (GST_MEMORY_FLAG_LAST << 1) +} GstGLBufferFlags; + +/** + * GST_MAP_GL: + * + * Flag indicating that we should map the GL object instead of to system memory. + * + * Combining #GST_MAP_GL with #GST_MAP_WRITE has the same semantics as though + * you are writing to OpenGL. Conversely, combining #GST_MAP_GL with + * #GST_MAP_READ has the same semantics as though you are reading from OpenGL. + */ +#define GST_MAP_GL (GST_MAP_FLAG_LAST << 1) + +/** + * GstGLBuffer: + * @mem: the parent object + * @context: the #GstGLContext to use for GL operations + * @id: the buffer id for this memory + * @target: the GL target of this texture for binding purposes + * + * Represents information about a GL buffer + */ +struct _GstGLBuffer +{ + GstGLBaseMemory mem; + + guint id; + guint target; /* XXX: put this in the allocator? */ + guint usage_hints; /* XXX: put this in the allocator? */ +}; + +/** + * GstGLBufferAllocator + * + * Opaque #GstGLAllocator struct + */ +struct _GstGLBufferAllocator +{ + GstGLBaseMemoryAllocator parent; +}; + +/** + * GstGLBufferAllocatorClass: + * + * The #GstGLBufferAllocatorClass only contains private data + */ +struct _GstGLBufferAllocatorClass +{ + GstGLBaseMemoryAllocatorClass parent_class; +}; + +#define GST_CAPS_FEATURE_MEMORY_GL_BUFFER "memory:GLBuffer" + +/** + * GST_GL_BUFFER_ALLOCATOR_NAME: + * + * The name of the GL buffer allocator + */ +#define GST_GL_BUFFER_ALLOCATOR_NAME "GLBuffer" + +void gst_gl_buffer_init_once (void); +gboolean gst_is_gl_buffer (GstMemory * mem); + +GstGLBuffer * gst_gl_buffer_alloc (GstGLContext * context, + guint gl_target, + guint gl_usage, + GstAllocationParams * params, + gsize maxsize); + +G_END_DECLS + +#endif /* _GST_GL_BUFFER_H_ */ diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index ffb3f786f..10e9ef78e 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -141,6 +141,7 @@ gst_gl_display_init (GstGLDisplay * display) gst_gl_base_buffer_init_once (); gst_gl_memory_init (); + gst_gl_buffer_init_once (); #if GST_GL_HAVE_PLATFORM_EGL gst_egl_image_memory_init (); |