d3d11decoder: Add support for array of texture DPB
authorSeungha Yang <seungha@centricular.com>
Sun, 29 Mar 2020 08:34:48 +0000 (17:34 +0900)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 30 Mar 2020 03:40:16 +0000 (03:40 +0000)
DXVA supports two kinds of texture structure for DPB, one is
"1) texture array" and the other is "2) array of texture".
1) is a type of texture which is single ID3D11Texture2D object having
ArraySize greater than one. So the ID3D11Texture2D itself is a set of texture.
Each sub texture of this type mush have identical resolution, format and so on,
and the number of sub texture in a texture array is fixed.

2) is an array of usual ID3D11Texture2D object. That means each
ID3D11Texture2D is independent each other and might have different resolution as well.
Moreover, we can modify the number of frames of the array dynamically.
This type is more flexible than "1) texture array" in terms of dynamic
behavior and also this type of texture can be used for shader resource view
but "1) texture array" couldn't be.

If "2) array of texture" is supported by driver, DXVA spec is saying that
it's preferred format over "1) texture array" in terms of performance.

sys/d3d11/gstd3d11decoder.c

index 05b5508db51084504d428a3523e0ed41aca079fc..2328a5542ee12181c9a7717fc55f9b95f4575e24 100644 (file)
@@ -81,6 +81,10 @@ struct _GstD3D11DecoderPrivate
   gint display_width;
   gint display_height;
 
+  gboolean use_array_of_texture;
+  guint pool_size;
+  guint8 next_view_id;
+
   /* for staging */
   ID3D11Texture2D *staging;
   gsize staging_texture_offset[GST_VIDEO_MAX_PLANES];
@@ -359,7 +363,8 @@ gst_d3d11_decoder_new (GstD3D11Device * device)
 static void
 gst_d3d11_decoder_output_view_free (GstD3D11DecoderOutputView * view)
 {
-  GST_DEBUG_OBJECT (view->device, "Free view %p", view);
+  GST_LOG_OBJECT (view->device, "Free view %p, view id: %d", view,
+      view->view_id);
 
   if (view->handle) {
     gst_d3d11_device_lock (view->device);
@@ -367,7 +372,7 @@ gst_d3d11_decoder_output_view_free (GstD3D11DecoderOutputView * view)
     gst_d3d11_device_unlock (view->device);
   }
 
-  gst_clear_object (&view->device);
+  gst_object_unref (view->device);
   g_free (view);
 }
 
@@ -381,34 +386,46 @@ gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
   GstD3D11DecoderOutputView *view;
   ID3D11VideoDecoderOutputView *view_handle;
   HRESULT hr;
+  guint view_id = 0;
 
   mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
 
   view = (GstD3D11DecoderOutputView *)
       gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
 
-  if (view)
+  if (view) {
+    GST_TRACE_OBJECT (self, "Reuse view id %d", view->view_id);
     return TRUE;
+  }
 
   view_desc.DecodeProfile = priv->decoder_profile;
   view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
   view_desc.Texture2D.ArraySlice = mem->subresource_index;
+  if (priv->use_array_of_texture) {
+    view_id = priv->next_view_id;
+
+    priv->next_view_id++;
+    /* valid view range is [0, 126] */
+    priv->next_view_id %= 127;
+  } else {
+    view_id = mem->subresource_index;
+  }
 
-  GST_LOG_OBJECT (self,
-      "Create decoder output view with index %d", mem->subresource_index);
+  GST_LOG_OBJECT (self, "Create decoder output view with index %d", view_id);
 
   hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (priv->video_device,
       (ID3D11Resource *) mem->texture, &view_desc, &view_handle);
   if (!gst_d3d11_result (hr, priv->device)) {
     GST_ERROR_OBJECT (self,
-        "Could not create decoder output view, hr: 0x%x", (guint) hr);
+        "Could not create decoder output view index %d, hr: 0x%x",
+        view_id, (guint) hr);
     return FALSE;
   }
 
   view = g_new0 (GstD3D11DecoderOutputView, 1);
   view->device = gst_object_ref (priv->device);
   view->handle = view_handle;
-  view->view_id = mem->subresource_index;
+  view->view_id = view_id;
 
   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK,
       view, (GDestroyNotify) gst_d3d11_decoder_output_view_free);
@@ -428,25 +445,35 @@ gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self,
   GstStructure *config = NULL;
   GstCaps *caps = NULL;
   GstVideoAlignment align;
+  GstD3D11AllocationFlags alloc_flags = 0;
+  gint bind_flags = D3D11_BIND_DECODER;
 
   gst_clear_object (&priv->internal_pool);
 
+  if (!priv->use_array_of_texture) {
+    alloc_flags = GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY;
+  } else {
+    /* array of texture can have shader resource view */
+    bind_flags |= D3D11_BIND_SHADER_RESOURCE;
+  }
+
   alloc_params = gst_d3d11_allocation_params_new (priv->device, info,
-      GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY, D3D11_BIND_DECODER);
+      alloc_flags, bind_flags);
 
   if (!alloc_params) {
     GST_ERROR_OBJECT (self, "Failed to create allocation param");
     goto error;
   }
 
-  alloc_params->desc[0].ArraySize = pool_size;
+  if (!priv->use_array_of_texture)
+    alloc_params->desc[0].ArraySize = pool_size;
   gst_video_alignment_reset (&align);
 
   align.padding_right = coded_width - GST_VIDEO_INFO_WIDTH (info);
   align.padding_bottom = coded_height - GST_VIDEO_INFO_HEIGHT (info);
   if (!gst_d3d11_allocation_params_alignment (alloc_params, &align)) {
     GST_ERROR_OBJECT (self, "Cannot set alignment");
-    return FALSE;
+    goto error;
   }
 
   pool = gst_d3d11_buffer_pool_new (priv->device);
@@ -481,6 +508,7 @@ gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self,
   }
 
   priv->internal_pool = pool;
+  priv->pool_size = pool_size;
 
   return TRUE;
 
@@ -618,6 +646,7 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
 
   priv = decoder->priv;
   decoder->opened = FALSE;
+  priv->use_array_of_texture = FALSE;
 
   d3d11_format = gst_d3d11_device_format_from_gst (priv->device,
       GST_VIDEO_INFO_FORMAT (info));
@@ -711,6 +740,16 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
     goto error;
   }
 
+  GST_DEBUG_OBJECT (decoder, "ConfigDecoderSpecific 0x%x",
+      best_config->ConfigDecoderSpecific);
+
+  /* bit 14 is equal to 1b means this config support array of texture and
+   * it's recommended type as per DXVA spec */
+  if ((best_config->ConfigDecoderSpecific & 0x4000) == 0x4000) {
+    GST_DEBUG_OBJECT (decoder, "Config support array of texture");
+    priv->use_array_of_texture = TRUE;
+  }
+
   if (!gst_d3d11_decoder_prepare_output_view_pool (decoder,
           info, aligned_width, aligned_height, pool_size, &selected_profile)) {
     GST_ERROR_OBJECT (decoder, "Couldn't prepare output view pool");
@@ -1130,6 +1169,7 @@ copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
   if (need_convert) {
     D3D11_BOX src_box;
     RECT rect;
+    ID3D11ShaderResourceView **srv = NULL;
 
     GST_LOG_OBJECT (self, "convert resolution, %dx%d -> %dx%d",
         display_width, display_height,
@@ -1142,11 +1182,24 @@ copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
     src_box.right = GST_ROUND_UP_2 (display_width);
     src_box.bottom = GST_ROUND_UP_2 (display_height);
 
-    /* copy decoded texture into shader resource texture */
-    ID3D11DeviceContext_CopySubresourceRegion (device_context,
-        (ID3D11Resource *) priv->shader_resource_texture, 0, 0, 0, 0,
-        (ID3D11Resource *) in_mem->texture, in_mem->subresource_index,
-        &src_box);
+    /* array of texture can be used for shader resource view */
+    if (priv->use_array_of_texture &&
+        gst_d3d11_memory_ensure_shader_resource_view (in_mem)) {
+      GST_TRACE_OBJECT (self, "Decoded texture supports shader resource view");
+      srv = in_mem->shader_resource_view;
+    }
+
+    if (!srv) {
+      /* copy decoded texture into shader resource texture */
+      GST_TRACE_OBJECT (self,
+          "Copy decoded texture to internal shader texture");
+      ID3D11DeviceContext_CopySubresourceRegion (device_context,
+          (ID3D11Resource *) priv->shader_resource_texture, 0, 0, 0, 0,
+          (ID3D11Resource *) in_mem->texture, in_mem->subresource_index,
+          &src_box);
+
+      srv = priv->shader_resource_view;
+    }
 
     rect.left = 0;
     rect.top = 0;
@@ -1156,7 +1209,7 @@ copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
     gst_d3d11_color_converter_update_crop_rect (priv->converter, &rect);
 
     if (!gst_d3d11_color_converter_convert_unlocked (priv->converter,
-            priv->shader_resource_view, priv->fallback_render_target_view)) {
+            srv, priv->fallback_render_target_view)) {
       GST_ERROR_OBJECT (self, "Failed to convert");
       goto error;
     }
@@ -1248,6 +1301,7 @@ copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
   if (need_convert) {
     gboolean need_copy = FALSE;
     ID3D11RenderTargetView **rtv;
+    ID3D11ShaderResourceView **srv = NULL;
     RECT rect;
 
     GST_LOG_OBJECT (self, "convert resolution, %dx%d -> %dx%d",
@@ -1266,10 +1320,23 @@ copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
     src_box.right = GST_ROUND_UP_2 (display_width);
     src_box.bottom = GST_ROUND_UP_2 (display_height);
 
-    /* copy decoded texture into shader resource texture */
-    ID3D11DeviceContext_CopySubresourceRegion (device_context,
-        (ID3D11Resource *) priv->shader_resource_texture, 0, 0, 0, 0,
-        (ID3D11Resource *) in_texture, in_subresource_index, &src_box);
+    /* array of texture can be used for shader resource view */
+    if (priv->use_array_of_texture &&
+        gst_d3d11_memory_ensure_shader_resource_view (in_mem)) {
+      GST_TRACE_OBJECT (self, "Decoded texture supports shader resource view");
+      srv = in_mem->shader_resource_view;
+    }
+
+    if (!srv) {
+      /* copy decoded texture into shader resource texture */
+      GST_TRACE_OBJECT (self,
+          "Copy decoded texture to internal shader texture");
+      ID3D11DeviceContext_CopySubresourceRegion (device_context,
+          (ID3D11Resource *) priv->shader_resource_texture, 0, 0, 0, 0,
+          (ID3D11Resource *) in_texture, in_mem->subresource_index, &src_box);
+
+      srv = priv->shader_resource_view;
+    }
 
     rect.left = 0;
     rect.top = 0;
@@ -1278,8 +1345,7 @@ copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info, gint display_width,
 
     gst_d3d11_color_converter_update_crop_rect (priv->converter, &rect);
 
-    if (!gst_d3d11_color_converter_convert_unlocked (priv->converter,
-            priv->shader_resource_view, rtv)) {
+    if (!gst_d3d11_color_converter_convert_unlocked (priv->converter, srv, rtv)) {
       GST_ERROR_OBJECT (self, "Failed to convert");
       goto error;
     }