allocators: Add DMABuf synchronization

When doing CPU Access, some architecture may require caches to be
synchronize before use. Otherwise, some visual artifact may be
visible, as the CPU modification may still resides in cache.

https://bugzilla.gnome.org/show_bug.cgi?id=794216

BUG: 148221549
Change-Id: I0d54d8368d9ed5855721852493183ee88205929d
diff --git a/configure.ac b/configure.ac
index 1287583..1248695 100644
--- a/configure.ac
+++ b/configure.ac
@@ -486,6 +486,9 @@
 dnl Check for mmap (needed by allocators library)
 AC_CHECK_FUNC([mmap], [AC_DEFINE(HAVE_MMAP, 1, [Defined if mmap is supported])])
 
+dnl Check for DMABuf synchronization ioctl (needed for DMABuf CPU access)
+AC_CHECK_HEADERS([linux/dma-buf.h], [])
+
 dnl *** plug-ins to include ***
 
 dnl these are all the gst plug-ins, compilable without additional libs
diff --git a/gst-libs/gst/allocators/gstdmabuf.c b/gst-libs/gst/allocators/gstdmabuf.c
index 170267b..e9c5dd3 100644
--- a/gst-libs/gst/allocators/gstdmabuf.c
+++ b/gst-libs/gst/allocators/gstdmabuf.c
@@ -34,9 +34,9 @@
  * Since: 1.2
  */
 
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#include <unistd.h>
+#ifdef HAVE_LINUX_DMA_BUF_H
+#include <sys/ioctl.h>
+#include <linux/dma-buf.h>
 #endif
 
 GST_DEBUG_CATEGORY_STATIC (dmabuf_debug);
@@ -44,6 +44,57 @@
 
 G_DEFINE_TYPE (GstDmaBufAllocator, gst_dmabuf_allocator, GST_TYPE_FD_ALLOCATOR);
 
+static gpointer
+gst_dmabuf_mem_map (GstMemory * gmem, GstMapInfo * info, gsize maxsize)
+{
+  GstAllocator *allocator = gmem->allocator;
+#ifdef HAVE_LINUX_DMA_BUF_H
+  struct dma_buf_sync sync = { DMA_BUF_SYNC_START };
+  gpointer ret;
+
+  if (info->flags & GST_MAP_READ)
+    sync.flags |= DMA_BUF_SYNC_READ;
+
+  if (info->flags & GST_MAP_WRITE)
+    sync.flags |= DMA_BUF_SYNC_WRITE;
+#endif
+
+  ret = allocator->mem_map (gmem, maxsize, info->flags);
+
+#ifdef HAVE_LINUX_DMA_BUF_H
+  if (ret) {
+    if (ioctl (gst_fd_memory_get_fd (gmem), DMA_BUF_IOCTL_SYNC, &sync) < 0)
+      GST_WARNING_OBJECT (allocator, "Failed to synchronize DMABuf: %s (%i)",
+          g_strerror (errno), errno);
+  }
+#endif
+
+  return ret;
+}
+
+static void
+gst_dmabuf_mem_unmap (GstMemory * gmem, GstMapInfo * info)
+{
+  GstAllocator *allocator = gmem->allocator;
+#ifdef HAVE_LINUX_DMA_BUF_H
+  struct dma_buf_sync sync = { DMA_BUF_SYNC_END };
+
+  if (info->flags & GST_MAP_READ)
+    sync.flags |= DMA_BUF_SYNC_READ;
+
+  if (info->flags & GST_MAP_WRITE)
+    sync.flags |= DMA_BUF_SYNC_WRITE;
+
+  if (ioctl (gst_fd_memory_get_fd (gmem), DMA_BUF_IOCTL_SYNC, &sync) < 0)
+    GST_WARNING_OBJECT (allocator, "Failed to synchronize DMABuf: %s (%i)",
+        g_strerror (errno), errno);
+#else
+  GST_WARNING_OBJECT (allocator, "Using DMABuf without synchronization.");
+#endif
+
+  allocator->mem_unmap (gmem);
+}
+
 static void
 gst_dmabuf_allocator_class_init (GstDmaBufAllocatorClass * klass)
 {
@@ -55,6 +106,8 @@
   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
 
   alloc->mem_type = GST_ALLOCATOR_DMABUF;
+  alloc->mem_map_full = gst_dmabuf_mem_map;
+  alloc->mem_unmap_full = gst_dmabuf_mem_unmap;
 }
 
 /**
diff --git a/meson.build b/meson.build
index 048cc35..da0776a 100644
--- a/meson.build
+++ b/meson.build
@@ -79,6 +79,7 @@
   ['HAVE_UNISTD_H', 'unistd.h'],
   ['HAVE_WINSOCK2_H', 'winsock2.h'],
   ['HAVE_XMMINTRIN_H', 'xmmintrin.h'],
+  ['HAVE_LINUX_DMA_BUF_H', 'linux/dma-buf.h'],
 ]
 foreach h : check_headers
   if cc.has_header(h.get(1))