va: Use the GstVaSurfaceCopy of the allocator atomically.
authorHe Junyan <junyan.he@intel.com>
Tue, 23 Nov 2021 13:10:55 +0000 (21:10 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 29 Nov 2021 19:25:31 +0000 (19:25 +0000)
The mem_copy() of the allocator can be called simultaneously from
different threads. We should use atomic pointer operations to create
and use the GstVaSurfaceCopy of the allocator.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1373>

subprojects/gst-plugins-bad/sys/va/gstvaallocator.c

index f977786..1b4c1f2 100644 (file)
@@ -258,6 +258,27 @@ struct _GstVaDmabufAllocator
 G_DEFINE_TYPE_WITH_CODE (GstVaDmabufAllocator, gst_va_dmabuf_allocator,
     GST_TYPE_DMABUF_ALLOCATOR, _init_debug_category ());
 
+static GstVaSurfaceCopy *
+_ensure_surface_copy (GstVaSurfaceCopy ** old, GstVaDisplay * display,
+    GstVideoInfo * info)
+{
+  GstVaSurfaceCopy *surface_copy;
+
+  surface_copy = g_atomic_pointer_get (old);
+  if (!surface_copy) {
+    surface_copy = gst_va_surface_copy_new (display, info);
+
+    /* others create a new one and set it before us */
+    if (surface_copy &&
+        !g_atomic_pointer_compare_and_exchange (old, NULL, surface_copy)) {
+      gst_va_surface_copy_free (surface_copy);
+      surface_copy = g_atomic_pointer_get (old);
+    }
+  }
+
+  return surface_copy;
+}
+
 /* If a buffer contains multiple memories (dmabuf objects) its very
  * difficult to provide a realiable way to fast-copy single memories:
  * While VA API sees surfaces with dependant dmabufs, GStreamer only
@@ -294,6 +315,7 @@ gst_va_dmabuf_mem_copy (GstMemory * gmem, gssize offset, gssize size)
   if (offset == 0 && size == mem_size && buf->n_mems == 1) {
     GstVaBufferSurface *buf_copy = NULL;
     GstMemory *copy;
+    GstVaSurfaceCopy *copy_func;
 
     GST_VA_MEMORY_POOL_LOCK (&self->pool);
     copy = gst_va_memory_pool_pop (&self->pool);
@@ -325,9 +347,8 @@ gst_va_dmabuf_mem_copy (GstMemory * gmem, gssize offset, gssize size)
 
     g_assert (buf_copy->n_mems == 1);
 
-    if (!self->copy)
-      self->copy = gst_va_surface_copy_new (self->display, &self->info);
-    if (self->copy && gst_va_surface_copy (self->copy, buf_copy->surface,
+    copy_func = _ensure_surface_copy (&self->copy, self->display, &self->info);
+    if (copy_func && gst_va_surface_copy (copy_func, buf_copy->surface,
             buf->surface))
       return copy;
 
@@ -1283,15 +1304,13 @@ _va_copy (GstMemory * mem, gssize offset, gssize size)
     size = mem_size > offset ? mem_size - offset : 0;
 
   if (offset == 0 && size == mem_size) {
-    if (!va_allocator->copy) {
-      va_allocator->copy =
-          gst_va_surface_copy_new (va_allocator->display, &va_allocator->info);
-    }
-    if (va_allocator->copy
-        && gst_va_surface_copy (va_allocator->copy, va_copy->surface,
-            va_mem->surface)) {
+    GstVaSurfaceCopy *copy_func;
+
+    copy_func = _ensure_surface_copy (&va_allocator->copy,
+        va_allocator->display, &va_allocator->info);
+    if (copy_func
+        && gst_va_surface_copy (copy_func, va_copy->surface, va_mem->surface))
       return copy;
-    }
   }
 
   if (!gst_memory_map (mem, &sinfo, GST_MAP_READ)) {