d3d11memory: Implement ID3D11VideoDecoderOutputView pool
authorSeungha Yang <seungha@centricular.com>
Mon, 19 Oct 2020 16:59:35 +0000 (01:59 +0900)
committerSeungha Yang <seungha@centricular.com>
Tue, 20 Oct 2020 08:56:52 +0000 (17:56 +0900)
Similar to texture-array pool, we can reuse decoder output view
since the life time of output view is identical to that of texture-array.
In this way, we can avoid frequent output view alloc/free.

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

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

index 2c99fb5..b9f98dd 100644 (file)
@@ -187,6 +187,7 @@ struct _GstD3D11AllocatorPrivate
   /* parent texture when array typed memory is used */
   ID3D11Texture2D *texture;
   GArray *array_in_use;
+  GArray *decoder_output_view_array;
 
   GMutex lock;
   GCond cond;
@@ -457,6 +458,9 @@ gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
     dmem->shader_resource_view[i] = NULL;
   }
 
+  if (dmem->decoder_output_view)
+    ID3D11VideoDecoderOutputView_Release (dmem->decoder_output_view);
+
   if (dmem->texture)
     ID3D11Texture2D_Release (dmem->texture);
 
@@ -475,6 +479,8 @@ gst_d3d11_allocator_dispose (GObject * object)
   GstD3D11Allocator *alloc = GST_D3D11_ALLOCATOR (object);
   GstD3D11AllocatorPrivate *priv = alloc->priv;
 
+  g_clear_pointer (&priv->decoder_output_view_array, g_array_unref);
+
   if (alloc->device && priv->texture) {
     gst_d3d11_device_release_texture (alloc->device, priv->texture);
     priv->texture = NULL;
@@ -735,6 +741,15 @@ error:
   mem->num_render_target_views = 0;
 }
 
+static void
+gst_d3d11_decoder_output_view_clear (ID3D11VideoDecoderOutputView ** view)
+{
+  if (view && *view) {
+    ID3D11VideoDecoderOutputView_Release (*view);
+    *view = NULL;
+  }
+}
+
 GstMemory *
 gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
     const D3D11_TEXTURE2D_DESC * desc, GstD3D11AllocationFlags flags,
@@ -770,6 +785,15 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
       priv->array_in_use = g_array_sized_new (FALSE,
           TRUE, sizeof (guint8), desc->ArraySize);
       g_array_set_size (priv->array_in_use, desc->ArraySize);
+
+      if ((desc->BindFlags & D3D11_BIND_DECODER) == D3D11_BIND_DECODER &&
+          !priv->decoder_output_view_array) {
+        priv->decoder_output_view_array = g_array_sized_new (FALSE,
+            TRUE, sizeof (ID3D11VideoDecoderOutputView *), desc->ArraySize);
+        g_array_set_clear_func (priv->decoder_output_view_array,
+            (GDestroyNotify) gst_d3d11_decoder_output_view_clear);
+        g_array_set_size (priv->decoder_output_view_array, desc->ArraySize);
+      }
     }
 
     for (i = 0; i < desc->ArraySize; i++) {
@@ -945,3 +969,96 @@ gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
 
   return ! !mem->num_render_target_views;
 }
+
+gboolean
+gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
+    ID3D11VideoDevice * video_device, GUID * decoder_profile)
+{
+  GstD3D11Allocator *allocator;
+  GstD3D11AllocatorPrivate *priv;
+  D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
+  ID3D11VideoDecoderOutputView *view = NULL;
+  HRESULT hr;
+
+  g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+  g_return_val_if_fail (video_device != NULL, FALSE);
+  g_return_val_if_fail (decoder_profile != NULL, FALSE);
+
+  allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
+  priv = allocator->priv;
+
+  if (mem->decoder_output_view) {
+    ID3D11VideoDecoderOutputView_GetDesc (mem->decoder_output_view, &desc);
+    if (IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
+      return TRUE;
+    } else {
+      /* Shouldn't happen, but try again anyway */
+      GST_WARNING_OBJECT (allocator,
+          "Existing view has different decoder profile");
+      ID3D11VideoDecoderOutputView_Release (mem->decoder_output_view);
+      mem->decoder_output_view = NULL;
+    }
+  }
+
+  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) {
+    view = g_array_index (priv->decoder_output_view_array,
+        ID3D11VideoDecoderOutputView *, mem->subresource_index);
+
+    if (view) {
+      ID3D11VideoDecoderOutputView_GetDesc (view, &desc);
+      /* Shouldn't happen because decoder will not reuse this allocator
+       * over different codec/profiles */
+      if (!IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
+        GST_WARNING_OBJECT (allocator,
+            "Existing view has different decoder profile");
+        ID3D11VideoDecoderOutputView_Release (view);
+        view = NULL;
+        g_array_index (priv->decoder_output_view_array,
+            ID3D11VideoDecoderOutputView *, mem->subresource_index) = NULL;
+      }
+    }
+  }
+
+  /* Increase refcount and reuse existing view */
+  if (view) {
+    mem->decoder_output_view = view;
+    ID3D11VideoDecoderOutputView_AddRef (view);
+
+    return TRUE;
+  }
+
+  desc.DecodeProfile = *decoder_profile;
+  desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
+  desc.Texture2D.ArraySlice = mem->subresource_index;
+
+  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,
+        "Could not create decoder output view, hr: 0x%x", (guint) hr);
+    return FALSE;
+  }
+
+  /* Store view array for later reuse */
+  if (priv->decoder_output_view_array) {
+    view = g_array_index (priv->decoder_output_view_array,
+        ID3D11VideoDecoderOutputView *, mem->subresource_index);
+
+    if (view)
+      ID3D11VideoDecoderOutputView_Release (view);
+
+    g_array_index (priv->decoder_output_view_array,
+        ID3D11VideoDecoderOutputView *, mem->subresource_index) =
+        mem->decoder_output_view;
+    ID3D11VideoDecoderOutputView_AddRef (mem->decoder_output_view);
+  }
+
+  return TRUE;
+}
index 42da320..d3a1510 100644 (file)
@@ -113,6 +113,8 @@ struct _GstD3D11Memory
   ID3D11RenderTargetView *render_target_view[GST_VIDEO_MAX_PLANES];
   guint num_render_target_views;
 
+  ID3D11VideoDecoderOutputView *decoder_output_view;
+
   GstD3D11MemoryType type;
 
   /* > 0 if this is Array typed memory */
@@ -183,6 +185,10 @@ gboolean            gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory
 
 gboolean            gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem);
 
+gboolean            gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
+                                                                 ID3D11VideoDevice * video_device,
+                                                                 GUID * decoder_profile);
+
 G_END_DECLS
 
 #endif /* __GST_D3D11_MEMORY_H__ */