gldownload: accelerate with dma-buf textures

For the formats supported by the GPU stack, allocate dma-bufs for
the texture to download and have upstream render to it. Downloading
then becomes the task to sync dma-buf access before CPU acces (mmap).

Note:
Currently driver supports only RGBA/BGRA, not RGB/BGR.

Change-Id: I04d45d2ba0780a60f5be22b5a48a4c8ba6ca69c7
diff --git a/ext/gl/gstgldownloadelement.c b/ext/gl/gstgldownloadelement.c
index aefc289..37e4fff 100644
--- a/ext/gl/gstgldownloadelement.c
+++ b/ext/gl/gstgldownloadelement.c
@@ -26,6 +26,7 @@
 #if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
 #include <gst/gl/egl/gsteglimage.h>
 #include <gst/allocators/gstdmabuf.h>
+#include <gst/gl/gstglmemorydma.h>
 #endif
 
 #include "gstgldownloadelement.h"
@@ -50,6 +51,8 @@
     GstBuffer * buffer, GstBuffer ** outbuf);
 static GstFlowReturn gst_gl_download_element_transform (GstBaseTransform * bt,
     GstBuffer * buffer, GstBuffer * outbuf);
+static gboolean gst_gl_download_element_propose_allocation (GstBaseTransform *
+    trans, GstQuery * decide_query, GstQuery * query);
 static gboolean gst_gl_download_element_decide_allocation (GstBaseTransform *
     trans, GstQuery * query);
 static void gst_gl_download_element_finalize (GObject * object);
@@ -88,6 +91,7 @@
       gst_gl_download_element_prepare_output_buffer;
   bt_class->transform = gst_gl_download_element_transform;
   bt_class->decide_allocation = gst_gl_download_element_decide_allocation;
+  bt_class->propose_allocation = gst_gl_download_element_propose_allocation;
 
   bt_class->passthrough_on_same_caps = TRUE;
 
@@ -394,6 +398,13 @@
   GstGLDownloadElement *dl = GST_GL_DOWNLOAD_ELEMENT (bt);
   gint i, n;
 
+  if (gst_is_gl_memory_dma (gst_buffer_peek_memory (inbuf, 0))) {
+    GstBuffer *buf = gst_gl_memory_dma_sync_buffer (inbuf);
+    GST_BASE_TRANSFORM_GET_CLASS (bt)->copy_metadata (bt, inbuf, buf);
+    *outbuf = buf;
+    return GST_FLOW_OK;
+  }
+
   *outbuf = inbuf;
 
   if (dl->do_pbo_transfers) {
@@ -464,6 +475,94 @@
       query);
 }
 
+static gboolean
+gst_gl_download_element_propose_allocation (GstBaseTransform * trans,
+    GstQuery * decide_query, GstQuery * query)
+{
+  GstGLDownloadElement *dl;
+  GstGLContext *context;
+  GstAllocator *allocator;
+  GstCaps *caps;
+  GstVideoInfo info;
+  GstAllocationParams params;
+  GstVideoFormat format;
+  GstBufferPool *pool;
+  GstStructure *config;
+  GstMemory *mem;
+  guint n_pools, i;
+
+  dl = GST_GL_DOWNLOAD_ELEMENT_CAST (trans);
+  gst_query_parse_allocation (query, &caps, NULL);
+
+  if (!gst_video_info_from_caps (&info, caps)) {
+    GST_ERROR_OBJECT (trans, "invalid caps %" GST_PTR_FORMAT, caps);
+    goto base;
+  }
+
+  format = GST_VIDEO_INFO_FORMAT (&info);
+  GST_DEBUG_OBJECT (dl, "format %s", gst_video_format_to_string (format));
+
+  switch (format) {
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+      gst_gl_memory_dma_init_once ();
+      allocator =  gst_allocator_find (GST_GL_MEMORY_DMA_ALLOCATOR_NAME);
+      /* Ensure allocator works (i.e. ION is present) */
+      mem = gst_allocator_alloc (allocator, 1337, NULL);
+      if (mem) {
+        GST_DEBUG_OBJECT (dl, "downloading using dmabuf textures");
+        gst_memory_unref (mem);
+      } else {
+        GST_ERROR_OBJECT (dl, "dmabuf texture allocator not working");
+        gst_object_unref (allocator);
+        allocator = NULL;
+      }
+      break;
+    /* TODO: 24 bit formats are currently unsupported by the driver. */
+    case GST_VIDEO_FORMAT_BGR:
+    case GST_VIDEO_FORMAT_RGB:
+    default:
+      allocator = NULL;
+      break;
+  }
+
+  GST_DEBUG_OBJECT (dl, "allocator %p", allocator);
+
+  if (!allocator) {
+    goto base;
+  }
+
+  gst_allocation_params_init (&params);
+  gst_query_add_allocation_param (query, allocator, &params);
+  gst_object_unref (allocator);
+
+  n_pools = gst_query_get_n_allocation_pools (query);
+  for (i = 0; i < n_pools; ++i) {
+    gst_query_remove_nth_allocation_pool (query, i);
+  }
+
+  pool = gst_gl_buffer_pool_new (GST_GL_BASE_FILTER (trans)->context);
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, info.size, 0, 0);
+  gst_buffer_pool_config_add_option (config,
+      GST_BUFFER_POOL_OPTION_GL_SYNC_META);
+
+  if (!gst_buffer_pool_set_config (pool, config)) {
+    gst_object_unref (pool);
+    GST_ERROR_OBJECT (dl, "gst_buffer_pool_set_config failed");
+    goto base;
+  }
+
+  gst_query_add_allocation_pool (query, pool, info.size, 0, 0);
+  gst_object_unref (pool);
+
+  return TRUE;
+
+base:
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
+        decide_query, query);
+}
+
 static void
 gst_gl_download_element_finalize (GObject * object)
 {
diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am
index 4e77e8c..5a456d9 100644
--- a/gst-libs/gst/gl/Makefile.am
+++ b/gst-libs/gst/gl/Makefile.am
@@ -13,6 +13,7 @@
 	gstglbasememory.c \
 	gstglbuffer.c \
 	gstglmemory.c \
+	gstglmemorydma.c \
 	gstglmemorypbo.c \
 	gstglrenderbuffer.c \
 	gstglbufferpool.c \
@@ -44,6 +45,7 @@
 	gstglbasememory.h \
 	gstglbuffer.h \
 	gstglmemory.h \
+	gstglmemorydma.h \
 	gstglmemorypbo.h \
 	gstglrenderbuffer.h \
 	gstglbufferpool.h \
diff --git a/gst-libs/gst/gl/gstglmemorydma.c b/gst-libs/gst/gl/gstglmemorydma.c
new file mode 100644
index 0000000..5fbb24f
--- /dev/null
+++ b/gst-libs/gst/gl/gstglmemorydma.c
@@ -0,0 +1,374 @@
+/*
+ * # Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/gl/gstglfuncs.h>
+
+#include "gstglmemorydma.h"
+
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY_DMA);
+#define GST_CAT_DEFAULT GST_CAT_GL_MEMORY_DMA
+
+#define parent_class gst_gl_memory_dma_allocator_parent_class
+G_DEFINE_TYPE (GstGLMemoryDmaAllocator, gst_gl_memory_dma_allocator,
+    GST_TYPE_GL_MEMORY_ALLOCATOR);
+
+static void gst_gl_memory_dma_allocator_finalize (GObject * object);
+static GstGLBaseMemory *  _gl_mem_dma_alloc
+    (GstGLBaseMemoryAllocator * allocator, GstGLAllocationParams * params);
+static gboolean _gl_mem_dma_create (GstGLBaseMemory * glmem, GError ** error);
+static void _gl_mem_dma_destroy (GstGLBaseMemory * glmem);
+static GstMemory * _mem_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params);
+
+
+static void
+gst_gl_memory_dma_allocator_class_init (GstGLMemoryDmaAllocatorClass * klass)
+{
+  GST_ALLOCATOR_CLASS (klass)->alloc = _mem_alloc;
+
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (klass)->alloc = _gl_mem_dma_alloc;
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (klass)->create = _gl_mem_dma_create;
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (klass)->destroy = _gl_mem_dma_destroy;
+
+  G_OBJECT_CLASS (klass)->finalize = gst_gl_memory_dma_allocator_finalize;
+
+  GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_MEMORY_DMA, "glmemorydma", 0,
+    "OpenGL DMA memory");
+}
+
+static void
+gst_gl_memory_dma_allocator_init (GstGLMemoryDmaAllocator * alloc)
+{
+  GST_DEBUG_OBJECT (alloc, "init");
+  GST_ALLOCATOR (alloc)->mem_type = GST_GL_MEMORY_DMA_ALLOCATOR_NAME;
+  GST_OBJECT_FLAG_SET (GST_OBJECT (alloc), GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+
+  /* ION allocator is in the "coral" plugin, load it. */
+  alloc->plugin = gst_plugin_load_by_name ("coral");
+  if (!alloc->plugin) {
+    GST_ERROR_OBJECT (alloc, "coral plugin not found");
+    return;
+  }
+
+  alloc->ion_allocator = gst_allocator_find ("ion");
+  if (!alloc->ion_allocator) {
+    GST_ERROR_OBJECT (alloc, "ION allocator not found");
+    return;
+  }
+
+  GST_INFO_OBJECT (alloc, "ION allocator loaded");
+}
+
+static void
+gst_gl_memory_dma_allocator_finalize (GObject * object)
+{
+  GstGLMemoryDmaAllocator *alloc = GST_GL_MEMORY_DMA_ALLOCATOR (object);
+
+  GST_DEBUG_OBJECT (alloc, "finalize");
+
+  if (alloc->ion_allocator) {
+    gst_object_unref (alloc->ion_allocator);
+    alloc->ion_allocator = NULL;
+  }
+
+  if (alloc->plugin) {
+    gst_object_unref (alloc->plugin);
+    alloc->plugin = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstGLBaseMemory *
+ _gl_mem_dma_alloc (GstGLBaseMemoryAllocator * allocator,
+    GstGLAllocationParams * alloc_params)
+{
+  GstGLMemoryDmaAllocator *alloc;
+  GstGLMemoryDMA *dmamem;
+  GstGLVideoAllocationParams *params;
+  gsize size;
+
+  alloc = GST_GL_MEMORY_DMA_ALLOCATOR (allocator);
+  params = (GstGLVideoAllocationParams *) alloc_params;
+
+  g_return_val_if_fail (params->parent.alloc_flags &
+      GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO, NULL);
+
+  dmamem = g_new0 (GstGLMemoryDMA, 1);
+  dmamem->params = params->parent.alloc_params;
+
+  /* GstVideoInfo defaults to 4 b stride align for RGB/BGR but we want to
+   * pack the buffer as tightly as possible (i.e. stride == width * bpp).
+   */
+  switch (params->v_info->finfo->format) {
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+      params->v_info->stride[0] = params->v_info->width * 3;
+      params->v_info->size = params->v_info->stride[0] * params->v_info->height;
+      break;
+    default:
+      break;
+  }
+
+  size = gst_gl_get_plane_data_size (params->v_info, params->valign,
+      params->plane);
+  dmamem->dma = gst_allocator_alloc (alloc->ion_allocator, size,
+      dmamem->params);
+
+  if (!dmamem->dma) {
+    GST_CAT_ERROR (GST_CAT_GL_MEMORY_DMA, "ION alloc of %zu b failed", size);
+    g_free (dmamem);
+    return NULL;
+  }
+
+  GST_CAT_DEBUG (GST_CAT_GL_MEMORY_DMA, "ION alloc %zu b", size);
+
+  gst_gl_memory_init (GST_GL_MEMORY_CAST (dmamem), GST_ALLOCATOR_CAST (alloc),
+      NULL, params->parent.context, params->target, params->tex_format,
+      params->parent.alloc_params, params->v_info, params->plane,
+      params->valign, params->parent.user_data, params->parent.notify);
+
+  return GST_GL_BASE_MEMORY_CAST (dmamem);
+}
+
+static gboolean
+_gl_mem_dma_create (GstGLBaseMemory * glmem, GError ** error)
+{
+  GstGLMemoryDMA *dmamem;
+  const GstGLFuncs *gl;
+  gint fd;
+  guint tex_id;
+
+  g_return_val_if_fail (glmem, FALSE);
+  g_return_val_if_fail (glmem->context, FALSE);
+  gl = glmem->context->gl_vtable;
+
+  if (!GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class)->create (glmem,
+      error)) {
+    return FALSE;
+  }
+
+  dmamem = GST_GL_MEMORY_DMA_CAST (glmem);
+  fd = gst_dmabuf_memory_get_fd (dmamem->dma);
+  tex_id = GST_GL_MEMORY_CAST (&glmem->mem)->tex_id;
+
+  dmamem->image = gst_egl_image_from_dmabuf (glmem->context, fd,
+      &GST_GL_MEMORY_CAST (glmem)->info, 0, 0);
+  if (!dmamem->image) {
+    GST_CAT_ERROR (GST_CAT_GL_MEMORY_DMA, "gst_egl_image_from_dmabuf failed");
+    return FALSE;
+  }
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->BindTexture (GL_TEXTURE_2D, tex_id);
+  gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, gst_egl_image_get_image (
+      dmamem->image));
+
+  GST_CAT_DEBUG (GST_CAT_GL_MEMORY_DMA, "created dma mem %p fd %d tex_id %u",
+      glmem, fd, tex_id);
+
+  return TRUE;
+}
+
+static void
+_gl_mem_dma_destroy (GstGLBaseMemory * glmem)
+{
+  GstGLMemoryDMA *dmamem;
+
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class)->destroy (glmem);
+
+  dmamem = GST_GL_MEMORY_DMA_CAST (glmem);
+
+  if (dmamem->image) {
+    gst_egl_image_unref (dmamem->image);
+    dmamem->image = NULL;
+  }
+
+  if (dmamem->dma) {
+    gst_memory_unref (dmamem->dma);
+    dmamem->dma = NULL;
+  }
+
+  /* Base class frees dmamem. */
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class)->destroy (glmem);
+  GST_CAT_DEBUG (GST_CAT_GL_MEMORY_DMA, "destroyed dma mem %p", dmamem);
+}
+
+static GstMemory *
+_mem_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  /* Only used as an init check, does not support actual GL alloc. */
+
+  GstGLMemoryDmaAllocator *alloc;
+
+  alloc = GST_GL_MEMORY_DMA_ALLOCATOR (allocator);
+
+  g_return_val_if_fail (alloc->ion_allocator, NULL);
+
+  return gst_allocator_alloc (alloc->ion_allocator, size, params);
+}
+
+static EGLDisplay
+_get_egl_display (GstGLContext * context)
+{
+  EGLDisplay egl_display;
+  GstGLDisplayEGL *display_egl;
+  if (!context->display) {
+    return EGL_NO_DISPLAY;
+  }
+  display_egl = gst_gl_display_egl_from_gl_display (context->display);
+  egl_display =
+      (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (display_egl));
+  gst_object_unref (display_egl);
+  return egl_display;
+}
+
+static EGLSyncKHR
+_eglCreateSyncKHR (GstGLContext * context)
+{
+  GstClockTime ts;
+  EGLSyncKHR sync;
+  EGLSyncKHR (*gst_eglCreateSyncKHR) (EGLDisplay dpy, EGLenum type,
+      const EGLAttrib * attrib_list);
+  EGLDisplay dpy = _get_egl_display (context);
+  g_assert (dpy != EGL_NO_DISPLAY);
+
+  ts = gst_util_get_timestamp ();
+  gst_eglCreateSyncKHR = gst_gl_context_get_proc_address (context,
+        "eglCreateSyncKHR");
+  sync = gst_eglCreateSyncKHR (dpy, EGL_SYNC_FENCE_KHR, NULL);
+  GST_CAT_LOG (GST_CAT_GL_MEMORY_DMA, "created egl sync object %p", sync);
+  ts = gst_util_get_timestamp () - ts;
+  GST_CAT_LOG (GST_CAT_GL_MEMORY_DMA, "create %.2g ms",(double) ts / GST_MSECOND);
+  return sync;
+}
+
+static EGLBoolean
+_eglClientWaitSyncKHR (GstGLContext * context, EGLSyncKHR sync)
+{
+  EGLint (*gst_eglClientWaitSyncKHR) (EGLDisplay dpy, EGLSyncKHR sync,
+        EGLint flags, EGLTimeKHR timeout);
+  EGLDisplay dpy = _get_egl_display (context);
+  g_assert (dpy != EGL_NO_DISPLAY);
+
+  GST_CAT_LOG (GST_CAT_GL_MEMORY_DMA, "waiting on egl sync object %p", sync);
+  gst_eglClientWaitSyncKHR = gst_gl_context_get_proc_address (context,
+        "eglClientWaitSyncKHR");
+  return gst_eglClientWaitSyncKHR (dpy, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+      1000000000 /* 1s */ ) == EGL_CONDITION_SATISFIED_KHR;
+}
+
+static EGLBoolean
+_eglDestroySyncKHR (GstGLContext * context, EGLSyncKHR sync)
+{
+  EGLBoolean (*gst_eglDestroySyncKHR) (EGLDisplay dpy, EGLSyncKHR sync);
+  EGLDisplay dpy = _get_egl_display (context);
+  if (dpy == EGL_NO_DISPLAY) {
+    return EGL_FALSE;
+  }
+
+  gst_eglDestroySyncKHR = gst_gl_context_get_proc_address (context,
+        "eglDestroySyncKHR");
+  GST_CAT_LOG (GST_CAT_GL_MEMORY_DMA, "deleting egl sync object %p", sync);
+  return gst_eglDestroySyncKHR (dpy, sync);
+}
+
+static void
+_create_sync_gl (GstGLContext * context, gpointer data)
+{
+  EGLSyncKHR *sync = (EGLSyncKHR *) data;
+  *sync = _eglCreateSyncKHR (context);
+}
+
+GstBuffer *
+gst_gl_memory_dma_sync_buffer (GstBuffer * glbuf)
+{
+  GstBuffer *buf;
+  GstVideoInfo *info;
+  GstMemory *mem;
+  GstGLBaseMemory *glmem;
+  GstGLMemoryDMA *dmamem;
+  GstGLSyncMeta *sync_meta;
+  EGLSyncKHR sync;
+  EGLBoolean res;
+  GstClockTime ts;
+
+  mem = gst_buffer_peek_memory (glbuf, 0);
+  g_assert (gst_is_gl_memory_dma (mem));
+
+  glmem = GST_GL_BASE_MEMORY_CAST (mem);
+  dmamem = GST_GL_MEMORY_DMA_CAST (mem);
+  sync_meta = gst_buffer_get_gl_sync_meta (glbuf);
+
+  if (sync_meta) {
+    ts = gst_util_get_timestamp ();
+    gst_gl_sync_meta_wait_cpu (sync_meta, glmem->context);
+    ts = gst_util_get_timestamp () - ts;
+    GST_CAT_DEBUG (GST_CAT_GL_MEMORY_DMA, "wait_cpu %.2g ms",
+        (double) ts / GST_MSECOND);
+  } else {
+    ts = gst_util_get_timestamp ();
+    gst_gl_context_thread_add (glmem->context, _create_sync_gl, &sync);
+    g_assert (sync != EGL_NO_SYNC_KHR);
+
+    do {
+      res = _eglClientWaitSyncKHR (glmem->context, sync);
+    } while (res == EGL_FALSE);
+    ts = gst_util_get_timestamp () - ts;
+
+    res = _eglDestroySyncKHR (glmem->context, sync);
+    g_assert (res == EGL_TRUE);
+    ts = gst_util_get_timestamp () - ts;
+    GST_CAT_DEBUG (GST_CAT_GL_MEMORY_DMA, "egl_sync %.2g ms",
+        (double) ts / GST_MSECOND);
+  }
+
+  info = &dmamem->mem.info;
+  buf = gst_buffer_new ();
+  gst_buffer_add_parent_buffer_meta (buf, glbuf);
+  gst_buffer_append_memory (buf, gst_memory_ref (dmamem->dma));
+  gst_buffer_add_video_meta_full (buf, 0,
+      GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
+      GST_VIDEO_INFO_HEIGHT (info), 1, info->offset, info->stride);
+
+  return buf;
+}
+
+gboolean
+gst_is_gl_memory_dma (GstMemory * mem)
+{
+  return mem && mem->allocator && g_type_is_a (G_OBJECT_TYPE (mem->allocator),
+      GST_TYPE_GL_MEMORY_DMA_ALLOCATOR);
+}
+
+void
+gst_gl_memory_dma_init_once (void)
+{
+  static volatile gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GstAllocator *alloc = g_object_new (GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, NULL);
+    gst_object_ref_sink (alloc);
+    gst_allocator_register (GST_GL_MEMORY_DMA_ALLOCATOR_NAME, alloc);
+    g_once_init_leave (&_init, 1);
+  }
+}
diff --git a/gst-libs/gst/gl/gstglmemorydma.h b/gst-libs/gst/gl/gstglmemorydma.h
new file mode 100644
index 0000000..8feb089
--- /dev/null
+++ b/gst-libs/gst/gl/gstglmemorydma.h
@@ -0,0 +1,86 @@
+/*
+ * # Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _GST_GL_MEMORY_DMA_H_
+#define _GST_GL_MEMORY_DMA_H_
+
+#include <gst/gst.h>
+#include <gst/gstallocator.h>
+#include <gst/gl/gl.h>
+#include <gst/gl/egl/gsteglimage.h>
+#include <gst/gl/egl/gstegl.h>
+#include <gst/gl/egl/gstgldisplay_egl.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_MEMORY_DMA_ALLOCATOR (gst_gl_memory_dma_allocator_get_type())
+
+#define GST_IS_GL_MEMORY_DMA_ALLOCATOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR))
+#define GST_IS_GL_MEMORY_DMA_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLMemoryDmaAllocatorClass))
+#define GST_GL_MEMORY_DMA_ALLOCATOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLMemoryDmaAllocator))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLAllocatorClass))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_CAST(obj)       ((GstGLMemoryDmaAllocator *)(obj))
+#define GST_GL_MEMORY_DMA_CAST(obj)                 ((GstGLMemoryDMA *)(obj))
+
+#define GST_GL_MEMORY_DMA_ALLOCATOR_NAME "glmemorydma"
+
+typedef struct _GstGLMemoryDMA GstGLMemoryDMA;
+typedef struct _GstGLMemoryDmaAllocator GstGLMemoryDmaAllocator;
+typedef struct _GstGLMemoryDmaAllocatorClass GstGLMemoryDmaAllocatorClass;
+
+struct _GstGLMemoryDMA
+{
+  GstGLMemory mem;
+
+  GstEGLImage *image;
+  GstMemory *dma;
+  GstAllocationParams *params;
+};
+
+struct _GstGLMemoryDmaAllocator
+{
+  GstGLMemoryAllocator alloc;
+
+  GstPlugin *plugin;
+  GstAllocator *ion_allocator;
+};
+
+struct _GstGLMemoryDmaAllocatorClass
+{
+  GstGLMemoryAllocatorClass parent_class;
+};
+
+GST_GL_API
+GType gst_gl_memory_dma_allocator_get_type(void);
+
+GST_GL_API
+gboolean gst_is_gl_memory_dma (GstMemory * mem);
+
+GST_GL_API
+GstBuffer * gst_gl_memory_dma_sync_buffer (GstBuffer * glbuf);
+
+GST_GL_API
+void gst_gl_memory_dma_init_once (void);
+
+G_END_DECLS
+
+#endif /* _GST_GL_MEMORY_DMA_H_ */
+
+
+
+
+