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, &params, 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;
}
/**
 * gst_gl_base_memory_memcpy:
 * @src: the source #GstGLBaseMemory
 * @dest: the destination #GstGLBaseMemory
 * @offset: the offset to start at
 * @size: the number of bytes to copy
 *
 * Returns: whether the copy suceeded.
 */
gboolean
gst_gl_base_memory_memcpy (GstGLBaseMemory * src, GstGLBaseMemory * dest,
    gssize offset, gssize size)
{
  GstMapInfo sinfo, dinfo;

  if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (dest)))
    return FALSE;

  if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ)) {
    GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY,
        "could not read map source memory %p", src);
    return FALSE;
  }

  if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE)) {
    GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY,
        "could not write map dest memory %p", dest);
    gst_memory_unmap ((GstMemory *) src, &sinfo);
    return FALSE;
  }

  if (size == -1)
    size = sinfo.size > offset ? sinfo.size - offset : 0;

  GST_CAT_DEBUG (GST_CAT_GL_BASE_MEMORY,
      "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, src, dest);
  memcpy (dinfo.data, sinfo.data + offset, size);
  gst_memory_unmap ((GstMemory *) dest, &dinfo);
  gst_memory_unmap ((GstMemory *) src, &sinfo);

  return TRUE;
}
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_BASE_MEMORY_TRANSFER_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;
}