d3d11memory: Protect view object with lock
authorSeungha Yang <seungha@centricular.com>
Sat, 24 Oct 2020 11:59:55 +0000 (20:59 +0900)
committerSeungha Yang <seungha@centricular.com>
Sat, 24 Oct 2020 15:38:52 +0000 (00:38 +0900)
Make resource allocation more thread-safe

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1718>

sys/d3d11/gstd3d11memory.c
sys/d3d11/gstd3d11memory.h

index fb2b735..e8ad62c 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug);
 #define GST_CAT_DEFAULT gst_d3d11_allocator_debug
 
+#define GST_D3D11_ALLOCATOR_GET_LOCK(a) (&(GST_D3D11_ALLOCATOR_CAST(a)->priv->lock))
+#define GST_D3D11_ALLOCATOR_LOCK(a) g_mutex_lock(GST_D3D11_ALLOCATOR_GET_LOCK(a))
+#define GST_D3D11_ALLOCATOR_UNLOCK(a) g_mutex_unlock(GST_D3D11_ALLOCATOR_GET_LOCK(a))
+
+#define GST_D3D11_MEMORY_CAST(m) ((GstD3D11Memory *) m)
+#define GST_D3D11_MEMORY_GET_LOCK(m) (&(GST_D3D11_MEMORY_CAST(m)->lock))
+#define GST_D3D11_MEMORY_LOCK(m) g_mutex_lock(GST_D3D11_MEMORY_GET_LOCK(m))
+#define GST_D3D11_MEMORY_UNLOCK(m) g_mutex_unlock(GST_D3D11_MEMORY_GET_LOCK(m))
+
 GstD3D11AllocationParams *
 gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
     GstD3D11AllocationFlags flags, gint bind_flags)
@@ -268,7 +277,7 @@ gst_d3d11_memory_map_staging (GstMemory * mem, GstMapFlags flags)
 {
   GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
 
-  g_mutex_lock (&dmem->lock);
+  GST_D3D11_MEMORY_LOCK (dmem);
   if (dmem->cpu_map_count == 0) {
     ID3D11DeviceContext *device_context =
         gst_d3d11_device_get_device_context_handle (dmem->device);
@@ -289,13 +298,13 @@ gst_d3d11_memory_map_staging (GstMemory * mem, GstMapFlags flags)
     gst_d3d11_device_unlock (dmem->device);
 
     if (!ret) {
-      g_mutex_unlock (&dmem->lock);
+      GST_D3D11_MEMORY_UNLOCK (dmem);
       return NULL;
     }
   }
 
   dmem->cpu_map_count++;
-  g_mutex_unlock (&dmem->lock);
+  GST_D3D11_MEMORY_UNLOCK (dmem);
 
   return dmem->map.pData;
 }
@@ -312,7 +321,7 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
     return gst_d3d11_memory_map_staging (mem, flags);
   }
 
-  g_mutex_lock (&dmem->lock);
+  GST_D3D11_MEMORY_LOCK (dmem);
   if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
     if (dmem->staging &&
         GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD)) {
@@ -332,7 +341,7 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
       GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
     g_assert (dmem->texture != NULL);
-    g_mutex_unlock (&dmem->lock);
+    GST_D3D11_MEMORY_UNLOCK (dmem);
 
     return dmem->texture;
   }
@@ -358,7 +367,7 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
 
     if (!map_cpu_access_data (dmem, map_type)) {
       GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
-      g_mutex_unlock (&dmem->lock);
+      GST_D3D11_MEMORY_UNLOCK (dmem);
 
       return NULL;
     }
@@ -370,7 +379,7 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
   GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
   dmem->cpu_map_count++;
-  g_mutex_unlock (&dmem->lock);
+  GST_D3D11_MEMORY_UNLOCK (dmem);
 
   return dmem->map.pData;
 }
@@ -395,13 +404,13 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
 {
   GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
 
-  g_mutex_lock (&dmem->lock);
+  GST_D3D11_MEMORY_LOCK (dmem);
   if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
     if (dmem->type != GST_D3D11_MEMORY_TYPE_STAGING &&
         (info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
       GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
 
-    g_mutex_unlock (&dmem->lock);
+    GST_D3D11_MEMORY_UNLOCK (dmem);
     return;
   }
 
@@ -411,13 +420,13 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
 
   dmem->cpu_map_count--;
   if (dmem->cpu_map_count > 0) {
-    g_mutex_unlock (&dmem->lock);
+    GST_D3D11_MEMORY_UNLOCK (dmem);
     return;
   }
 
   unmap_cpu_access_data (dmem);
 
-  g_mutex_unlock (&dmem->lock);
+  GST_D3D11_MEMORY_UNLOCK (dmem);
 }
 
 static GstMemory *
@@ -443,10 +452,10 @@ gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
   gint i;
 
   if (priv->array_in_use) {
-    g_mutex_lock (&priv->lock);
+    GST_D3D11_ALLOCATOR_LOCK (self);
     g_array_index (priv->array_in_use, guint8, dmem->subresource_index) = 0;
     g_cond_broadcast (&priv->cond);
-    g_mutex_unlock (&priv->lock);
+    GST_D3D11_ALLOCATOR_UNLOCK (self);
   }
 
   for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
@@ -594,7 +603,7 @@ calculate_mem_size (GstD3D11Device * device, ID3D11Texture2D * texture,
   return ret;
 }
 
-static void
+static gboolean
 create_shader_resource_views (GstD3D11Memory * mem)
 {
   gint i;
@@ -637,7 +646,7 @@ create_shader_resource_views (GstD3D11Memory * mem)
       break;
     default:
       g_assert_not_reached ();
-      break;
+      return FALSE;
   }
 
   if ((mem->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) ==
@@ -659,9 +668,11 @@ create_shader_resource_views (GstD3D11Memory * mem)
     }
 
     mem->num_shader_resource_views = num_views;
+
+    return TRUE;
   }
 
-  return;
+  return FALSE;
 
 error:
   for (i = 0; i < num_views; i++) {
@@ -671,9 +682,11 @@ error:
   }
 
   mem->num_shader_resource_views = 0;
+
+  return FALSE;
 }
 
-static void
+static gboolean
 create_render_target_views (GstD3D11Memory * mem)
 {
   gint i;
@@ -713,7 +726,7 @@ create_render_target_views (GstD3D11Memory * mem)
       break;
     default:
       g_assert_not_reached ();
-      break;
+      return FALSE;
   }
 
   if ((mem->desc.BindFlags & D3D11_BIND_RENDER_TARGET) ==
@@ -735,9 +748,11 @@ create_render_target_views (GstD3D11Memory * mem)
     }
 
     mem->num_render_target_views = num_views;
+
+    return TRUE;
   }
 
-  return;
+  return FALSE;
 
 error:
   for (i = 0; i < num_views; i++) {
@@ -747,6 +762,8 @@ error:
   }
 
   mem->num_render_target_views = 0;
+
+  return FALSE;
 }
 
 static void
@@ -806,10 +823,10 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
     gint i;
 
   do_again:
-    g_mutex_lock (&priv->lock);
+    GST_D3D11_ALLOCATOR_LOCK (allocator);
     if (priv->flushing) {
       GST_DEBUG_OBJECT (allocator, "we are flushing");
-      g_mutex_unlock (&priv->lock);
+      GST_D3D11_ALLOCATOR_UNLOCK (allocator);
 
       return NULL;
     }
@@ -847,13 +864,13 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
     if (i == desc->ArraySize) {
       GST_DEBUG_OBJECT (allocator, "All elements in array are used now");
       g_cond_wait (&priv->cond, &priv->lock);
-      g_mutex_unlock (&priv->lock);
+      GST_D3D11_ALLOCATOR_UNLOCK (allocator);
       goto do_again;
     }
 
     g_array_index (priv->array_in_use, guint8, index_to_use) = 1;
 
-    g_mutex_unlock (&priv->lock);
+    GST_D3D11_ALLOCATOR_UNLOCK (allocator);
 
     if (!priv->texture) {
       priv->texture = gst_d3d11_device_create_texture (device, desc, NULL);
@@ -958,10 +975,10 @@ gst_d3d11_allocator_set_flushing (GstD3D11Allocator * allocator,
 
   priv = allocator->priv;
 
-  g_mutex_lock (&priv->lock);
+  GST_D3D11_ALLOCATOR_LOCK (allocator);
   priv->flushing = flushing;
   g_cond_broadcast (&priv->cond);
-  g_mutex_unlock (&priv->lock);
+  GST_D3D11_ALLOCATOR_UNLOCK (allocator);
 }
 
 gboolean
@@ -974,41 +991,55 @@ gst_is_d3d11_memory (GstMemory * mem)
 gboolean
 gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
 {
-  g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+  gboolean ret = FALSE;
 
-  if (mem->num_shader_resource_views)
-    return TRUE;
+  g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
 
   if (!(mem->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE)) {
     GST_WARNING_OBJECT (GST_MEMORY_CAST (mem)->allocator,
         "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
-
     return FALSE;
   }
 
-  create_shader_resource_views (mem);
+  GST_D3D11_MEMORY_LOCK (mem);
+  if (mem->num_shader_resource_views) {
+    ret = TRUE;
+    goto done;
+  }
+
+  ret = create_shader_resource_views (mem);
 
-  return ! !mem->num_shader_resource_views;
+done:
+  GST_D3D11_MEMORY_UNLOCK (mem);
+
+  return ret;
 }
 
 gboolean
 gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
 {
-  g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+  gboolean ret = FALSE;
 
-  if (mem->num_render_target_views)
-    return TRUE;
+  g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
 
   if (!(mem->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
     GST_WARNING_OBJECT (GST_MEMORY_CAST (mem)->allocator,
         "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
-
     return FALSE;
   }
 
-  create_render_target_views (mem);
+  GST_D3D11_MEMORY_LOCK (mem);
+  if (mem->num_render_target_views) {
+    ret = TRUE;
+    goto done;
+  }
+
+  ret = create_render_target_views (mem);
 
-  return ! !mem->num_render_target_views;
+done:
+  GST_D3D11_MEMORY_UNLOCK (mem);
+
+  return ret;
 }
 
 gboolean
@@ -1020,6 +1051,7 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
   D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
   ID3D11VideoDecoderOutputView *view = NULL;
   HRESULT hr;
+  gboolean ret = FALSE;
 
   g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
   g_return_val_if_fail (video_device != NULL, FALSE);
@@ -1028,10 +1060,17 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
   allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
   priv = allocator->priv;
 
+  if (!(mem->desc.BindFlags & D3D11_BIND_DECODER)) {
+    GST_WARNING_OBJECT (allocator,
+        "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
+    return FALSE;
+  }
+
+  GST_D3D11_MEMORY_LOCK (mem);
   if (mem->decoder_output_view) {
     ID3D11VideoDecoderOutputView_GetDesc (mem->decoder_output_view, &desc);
     if (IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
-      return TRUE;
+      goto succeeded;
     } else {
       /* Shouldn't happen, but try again anyway */
       GST_WARNING_OBJECT (allocator,
@@ -1041,14 +1080,8 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
     }
   }
 
-  if (!(mem->desc.BindFlags & D3D11_BIND_DECODER)) {
-    GST_WARNING_OBJECT (allocator,
-        "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
-
-    return FALSE;
-  }
-
   if (priv->decoder_output_view_array) {
+    GST_D3D11_ALLOCATOR_LOCK (allocator);
     view = g_array_index (priv->decoder_output_view_array,
         ID3D11VideoDecoderOutputView *, mem->subresource_index);
 
@@ -1063,17 +1096,17 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
         view = NULL;
         g_array_index (priv->decoder_output_view_array,
             ID3D11VideoDecoderOutputView *, mem->subresource_index) = NULL;
+      } else {
+        /* Increase refcount and reuse existing view */
+        mem->decoder_output_view = view;
+        ID3D11VideoDecoderOutputView_AddRef (view);
       }
     }
+    GST_D3D11_ALLOCATOR_UNLOCK (allocator);
   }
 
-  /* Increase refcount and reuse existing view */
-  if (view) {
-    mem->decoder_output_view = view;
-    ID3D11VideoDecoderOutputView_AddRef (view);
-
-    return TRUE;
-  }
+  if (mem->decoder_output_view)
+    goto succeeded;
 
   desc.DecodeProfile = *decoder_profile;
   desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
@@ -1082,13 +1115,14 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
   hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (video_device,
       (ID3D11Resource *) mem->texture, &desc, &mem->decoder_output_view);
   if (!gst_d3d11_result (hr, mem->device)) {
-    GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+    GST_ERROR_OBJECT (allocator,
         "Could not create decoder output view, hr: 0x%x", (guint) hr);
-    return FALSE;
+    goto done;
   }
 
   /* Store view array for later reuse */
   if (priv->decoder_output_view_array) {
+    GST_D3D11_ALLOCATOR_LOCK (allocator);
     view = g_array_index (priv->decoder_output_view_array,
         ID3D11VideoDecoderOutputView *, mem->subresource_index);
 
@@ -1099,9 +1133,16 @@ gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
         ID3D11VideoDecoderOutputView *, mem->subresource_index) =
         mem->decoder_output_view;
     ID3D11VideoDecoderOutputView_AddRef (mem->decoder_output_view);
+    GST_D3D11_ALLOCATOR_UNLOCK (allocator);
   }
 
-  return TRUE;
+succeeded:
+  ret = TRUE;
+
+done:
+  GST_D3D11_MEMORY_UNLOCK (mem);
+
+  return ret;
 }
 
 gboolean
@@ -1114,6 +1155,7 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
   D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC desc;
   ID3D11VideoProcessorInputView *view = NULL;
   HRESULT hr;
+  gboolean ret = FALSE;
 
   g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
   g_return_val_if_fail (video_device != NULL, FALSE);
@@ -1122,28 +1164,32 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
   allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
   priv = allocator->priv;
 
-  if (mem->processor_input_view)
-    return TRUE;
-
   if (!check_bind_flags_for_processor_input_view (mem->desc.BindFlags)) {
     GST_WARNING_OBJECT (allocator,
         "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
     return FALSE;
   }
 
+  GST_D3D11_MEMORY_LOCK (mem);
+  if (mem->processor_input_view)
+    goto succeeded;
+
   if (priv->processor_input_view_array) {
+    GST_D3D11_ALLOCATOR_LOCK (allocator);
     view = g_array_index (priv->processor_input_view_array,
         ID3D11VideoProcessorInputView *, mem->subresource_index);
-  }
-
-  /* Increase refcount and reuse existing view */
-  if (view) {
-    mem->processor_input_view = view;
-    ID3D11VideoProcessorInputView_AddRef (view);
 
-    return TRUE;
+    /* Increase refcount and reuse existing view */
+    if (view) {
+      mem->processor_input_view = view;
+      ID3D11VideoProcessorInputView_AddRef (view);
+    }
+    GST_D3D11_ALLOCATOR_UNLOCK (allocator);
   }
 
+  if (mem->processor_input_view)
+    goto succeeded;
+
   desc.FourCC = 0;
   desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
   desc.Texture2D.MipSlice = 0;
@@ -1155,11 +1201,12 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
   if (!gst_d3d11_result (hr, mem->device)) {
     GST_ERROR_OBJECT (allocator,
         "Could not create processor input view, hr: 0x%x", (guint) hr);
-    return FALSE;
+    goto done;
   }
 
   /* Store view array for later reuse */
   if (priv->processor_input_view_array) {
+    GST_D3D11_ALLOCATOR_LOCK (allocator);
     view = g_array_index (priv->processor_input_view_array,
         ID3D11VideoProcessorInputView *, mem->subresource_index);
 
@@ -1170,9 +1217,16 @@ gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
         ID3D11VideoProcessorInputView *, mem->subresource_index) =
         mem->processor_input_view;
     ID3D11VideoProcessorInputView_AddRef (mem->processor_input_view);
+    GST_D3D11_ALLOCATOR_UNLOCK (allocator);
   }
 
-  return TRUE;
+succeeded:
+  ret = TRUE;
+
+done:
+  GST_D3D11_MEMORY_UNLOCK (mem);
+
+  return ret;
 }
 
 gboolean
@@ -1183,6 +1237,7 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
   GstD3D11Allocator *allocator;
   D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC desc = { 0, };
   HRESULT hr;
+  gboolean ret;
 
   g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
   g_return_val_if_fail (video_device != NULL, FALSE);
@@ -1190,9 +1245,6 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
 
   allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
 
-  if (mem->processor_output_view)
-    return TRUE;
-
   if (!(mem->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
     GST_WARNING_OBJECT (allocator,
         "Need BindFlags, current flag 0x%x", mem->desc.BindFlags);
@@ -1206,6 +1258,10 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
     return FALSE;
   }
 
+  GST_D3D11_MEMORY_LOCK (mem);
+  if (mem->processor_output_view)
+    goto succeeded;
+
   desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
   desc.Texture2D.MipSlice = 0;
 
@@ -1215,8 +1271,14 @@ gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
   if (!gst_d3d11_result (hr, mem->device)) {
     GST_ERROR_OBJECT (allocator,
         "Could not create processor input view, hr: 0x%x", (guint) hr);
-    return FALSE;
+    goto done;
   }
 
-  return TRUE;
+succeeded:
+  ret = TRUE;
+
+done:
+  GST_D3D11_MEMORY_UNLOCK (mem);
+
+  return ret;
 }
index 46d8ffa..01ce9e8 100644 (file)
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
 #define GST_IS_D3D11_ALLOCATOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_D3D11_ALLOCATOR))
 #define GST_IS_D3D11_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_D3D11_ALLOCATOR))
 #define GST_D3D11_ALLOCATOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_D3D11_ALLOCATOR, GstD3D11AllocatorClass))
+#define GST_D3D11_ALLOCATOR_CAST(obj)       ((GstD3D11Allocator *)obj)
 
 #define GST_D3D11_MEMORY_NAME "D3D11Memory"