gpointer data;
gsize plane_start;
- if (!GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD)) {
+ if ((gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_UPLOAD) == 0)
return;
- }
gl = context->gl_vtable;
gl->BindTexture (gl_target, 0);
- GST_MEMORY_FLAG_UNSET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD);
+ gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_UPLOAD;
}
static inline void
}
static gboolean
-_gl_mem_read_pixels (GstGLMemory * gl_mem, GstMapInfo * info,
- gsize size, gpointer read_pointer)
+_gl_mem_read_pixels (GstGLMemory * gl_mem, gpointer read_pointer)
{
GstGLContext *context = gl_mem->mem.context;
const GstGLFuncs *gl = context->gl_vtable;
if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
type = GL_UNSIGNED_SHORT_5_6_5;
+ /* FIXME: avoid creating a framebuffer every download/copy */
gl->GenFramebuffers (1, &fbo);
gl->BindFramebuffer (GL_FRAMEBUFFER, fbo);
return TRUE;
}
-static gpointer
-_pbo_download_transfer (GstGLMemory * gl_mem, GstMapInfo * info, gsize size)
+static gboolean
+_read_pixels_to_pbo (GstGLMemory * gl_mem)
{
- GstGLBaseBufferAllocatorClass *alloc_class;
- const GstGLFuncs *gl;
- gpointer data;
+ 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 NULL;
-
- GST_DEBUG ("downloading texture %u using pbo %u", gl_mem->tex_id,
- gl_mem->mem.id);
-
- alloc_class =
- GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class);
- gl = gl_mem->mem.context->gl_vtable;
+ return FALSE;
- if (GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD)
- && info->flags & GST_MAP_READ) {
+ 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, info, -1, (gpointer) plane_start)) {
+ if (!_gl_mem_read_pixels (gl_mem, (gpointer) plane_start)) {
gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
- return NULL;
+ 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;
+
+ GST_DEBUG ("downloading texture %u using pbo %u", gl_mem->tex_id,
+ gl_mem->mem.id);
+
+ alloc_class =
+ GST_GL_BASE_BUFFER_ALLOCATOR_CLASS (gst_gl_allocator_parent_class);
+
+ /* texture -> pbo */
+ if (info->flags & GST_MAP_READ)
+ 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;
{
GstGLContext *context = gl_mem->mem.context;
const GstGLFuncs *gl = context->gl_vtable;
- guint format, type;
if (size != -1 && size != ((GstMemory *) gl_mem)->maxsize)
return NULL;
gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) gl_mem);
- format = gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
- type = GL_UNSIGNED_BYTE;
- if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
- type = GL_UNSIGNED_SHORT_5_6_5;
+ if (info->flags & GST_MAP_READ
+ && gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) {
+ guint format, type;
- gl->BindTexture (gl_mem->tex_target, gl_mem->tex_id);
- gl->GetTexImage (gl_mem->tex_target, 0, format, type, gl_mem->mem.data);
- gl->BindTexture (gl_mem->tex_target, 0);
+ format = gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
+ type = GL_UNSIGNED_BYTE;
+ if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
+ type = GL_UNSIGNED_SHORT_5_6_5;
+
+ gl->BindTexture (gl_mem->tex_target, gl_mem->tex_id);
+ gl->GetTexImage (gl_mem->tex_target, 0, format, type, gl_mem->mem.data);
+ gl->BindTexture (gl_mem->tex_target, 0);
+ }
return gl_mem->mem.data;
}
gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) gl_mem);
- if (!_gl_mem_read_pixels (gl_mem, info, size, gl_mem->mem.data))
- return NULL;
+ if (info->flags & GST_MAP_READ
+ && gl_mem->transfer_state & GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD) {
+ if (!_gl_mem_read_pixels (gl_mem, gl_mem->mem.data))
+ return NULL;
+ }
return gl_mem->mem.data;
}
if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE) {
GST_TRACE ("mapping GL texture:%u for writing", gl_mem->tex_id);
- GST_MINI_OBJECT_FLAG_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD);
+ gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD;
}
- GST_MEMORY_FLAG_UNSET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD);
+ gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_UPLOAD;
data = &gl_mem->tex_id;
} else { /* not GL */
data = _gl_mem_map_cpu_access (gl_mem, info, maxsize);
if (info->flags & GST_MAP_WRITE)
- GST_MINI_OBJECT_FLAG_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD);
+ gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD;
+ gl_mem->transfer_state &= ~GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD;
}
return data;
if ((info->flags & GST_MAP_GL) == 0) {
_gl_mem_unmap_cpu_access (gl_mem, info);
if (info->flags & GST_MAP_WRITE)
- GST_MINI_OBJECT_FLAG_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD);
+ gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_UPLOAD;
} else {
if (info->flags & GST_MAP_WRITE)
- GST_MINI_OBJECT_FLAG_SET (gl_mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD);
+ gl_mem->transfer_state |= GST_GL_MEMORY_TRANSFER_NEED_DOWNLOAD;
}
}
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 };
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;
}
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;
}
mem = _gl_mem_new (_gl_allocator, NULL, context, NULL, info, valign, plane,
user_data, notify);
- mem = (GstGLMemory *) gst_gl_base_buffer_alloc_data ((GstGLBaseBuffer *) mem);
if (!mem)
return NULL;
- memcpy (mem->mem.data, data, ((GstMemory *) mem)->maxsize);
+ 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);
+ _read_pixels_to_pbo (gl_mem);
+ 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));
+
+ gst_gl_context_thread_add (gl_mem->mem.context,
+ (GstGLContextThreadFunc) _upload_transfer, gl_mem);
+}
+
gint
gst_gl_memory_get_texture_width (GstGLMemory * gl_mem)
{
((GstGLMemory *) mem)->tex_id, 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);
fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD));
GST_END_TEST;
+GST_START_TEST (test_separate_transfer)
+{
+ GstAllocator *gl_allocator;
+ GstVideoInfo v_info;
+ GstMemory *mem;
+ GstMapInfo info;
+
+ gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
+ 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, &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_memory_upload_transfer ((GstGLMemory *) mem);
+
+ fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
+ GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD));
+
+ fail_unless (gst_memory_map (mem, &info, GST_MAP_READ));
+
+ fail_unless (((gchar *) info.data)[0] == rgba_pixel[0]);
+ fail_unless (((gchar *) info.data)[1] == rgba_pixel[1]);
+ fail_unless (((gchar *) info.data)[2] == rgba_pixel[2]);
+ fail_unless (((gchar *) info.data)[3] == rgba_pixel[3]);
+
+ gst_memory_unmap (mem, &info);
+
+ /* FIXME: add download transfer */
+
+ if (gst_gl_context_get_error ())
+ printf ("%s\n", gst_gl_context_get_error ());
+ fail_if (gst_gl_context_get_error () != NULL);
+
+ gst_memory_unref (mem);
+ gst_object_unref (gl_allocator);
+}
+
+GST_END_TEST;
+
static Suite *
gst_gl_memory_suite (void)
{
tcase_add_checked_fixture (tc_chain, setup, teardown);
tcase_add_test (tc_chain, test_basic);
tcase_add_test (tc_chain, test_transfer);
+ tcase_add_test (tc_chain, test_separate_transfer);
return s;
}