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 = 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 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 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.plane, &src->mem.valign, 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 void _upload_memory (GstGLContext * context, GstGLMemory * gl_mem) { const GstGLFuncs *gl; GLenum gl_format, gl_type; if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_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); if (USING_OPENGL (context) || USING_GLES3 (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)); gl->BindTexture (GL_TEXTURE_2D, gl_mem->tex_id); gl->TexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, gl_mem->tex_width, GL_MEM_HEIGHT (gl_mem), gl_format, gl_type, gl_mem->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_TEXTURE_2D, 0); GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD); }
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 pbo_id; 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; 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)); gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo_id); gst_gl_memory_texsubimage (GST_GL_MEMORY_CAST (gl_mem), NULL); gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0); }
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; } }