d3d11memory: Implement GstAllocator::mem_copy method
authorSeungha Yang <seungha@centricular.com>
Sun, 6 Jun 2021 16:49:26 +0000 (01:49 +0900)
committerSeungha Yang <seungha@centricular.com>
Wed, 9 Jun 2021 16:20:32 +0000 (01:20 +0900)
There are a few places which require deep copy
(basesink on drain for example). Also this implementation can be
useful for future use case.
One probable future use case is that copying DPB texture to
another texture for in-place transform since our DPB texture is never
writable, and therefore copying is unavoidable.

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

gst-libs/gst/d3d11/gstd3d11_fwd.h
gst-libs/gst/d3d11/gstd3d11memory.c
gst-libs/gst/d3d11/gstd3d11memory.h

index 8b455d1..e4c6265 100644 (file)
@@ -67,6 +67,7 @@ typedef struct _GstD3D11MemoryPrivate GstD3D11MemoryPrivate;
 
 typedef struct _GstD3D11Allocator GstD3D11Allocator;
 typedef struct _GstD3D11AllocatorClass GstD3D11AllocatorClass;
+typedef struct _GstD3D11AllocatorPrivate GstD3D11AllocatorPrivate;
 
 typedef struct _GstD3D11PoolAllocator GstD3D11PoolAllocator;
 typedef struct _GstD3D11PoolAllocatorClass GstD3D11PoolAllocatorClass;
index 74137dd..8627d09 100644 (file)
@@ -1217,11 +1217,19 @@ gst_d3d11_memory_get_processor_output_view (GstD3D11Memory * mem,
 }
 
 /* GstD3D11Allocator */
+struct _GstD3D11AllocatorPrivate
+{
+  GstMemoryCopyFunction fallback_copy;
+};
+
 #define gst_d3d11_allocator_parent_class alloc_parent_class
-G_DEFINE_TYPE (GstD3D11Allocator, gst_d3d11_allocator, GST_TYPE_ALLOCATOR);
+G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Allocator,
+    gst_d3d11_allocator, GST_TYPE_ALLOCATOR);
 
 static GstMemory *gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator,
     gsize size, GstAllocationParams * params);
+static GstMemory *gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
+    GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc);
 static void gst_d3d11_allocator_free (GstAllocator * allocator,
     GstMemory * mem);
 
@@ -1234,16 +1242,107 @@ gst_d3d11_allocator_class_init (GstD3D11AllocatorClass * klass)
   allocator_class->free = gst_d3d11_allocator_free;
 }
 
+static GstMemory *
+gst_d3d11_memory_copy (GstMemory * mem, gssize offset, gssize size)
+{
+  GstD3D11Allocator *alloc = GST_D3D11_ALLOCATOR (mem->allocator);
+  GstD3D11AllocatorPrivate *priv = alloc->priv;
+  GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
+  GstD3D11Memory *copy_dmem;
+  GstD3D11Device *device = dmem->device;
+  ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
+  ID3D11DeviceContext *device_context =
+      gst_d3d11_device_get_device_context_handle (device);
+  D3D11_TEXTURE2D_DESC dst_desc = { 0, };
+  D3D11_TEXTURE2D_DESC src_desc = { 0, };
+  GstMemory *copy = NULL;
+  GstMapInfo info;
+  HRESULT hr;
+  UINT bind_flags = 0;
+  UINT supported_flags = 0;
+
+  /* non-zero offset or different size is not supported */
+  if (offset != 0 || (size != -1 && size != mem->size)) {
+    GST_DEBUG_OBJECT (alloc, "Different size/offset, try fallback copy");
+    return priv->fallback_copy (mem, offset, size);
+  }
+
+  gst_d3d11_device_lock (device);
+  if (!gst_memory_map (mem, &info, GST_MAP_READ | GST_MAP_D3D11)) {
+    gst_d3d11_device_unlock (device);
+
+    GST_WARNING_OBJECT (alloc, "Failed to map memory, try fallback copy");
+
+    return priv->fallback_copy (mem, offset, size);
+  }
+
+  ID3D11Texture2D_GetDesc (dmem->priv->texture, &src_desc);
+  dst_desc.Width = src_desc.Width;
+  dst_desc.Height = src_desc.Height;
+  dst_desc.MipLevels = 1;
+  dst_desc.Format = src_desc.Format;
+  dst_desc.SampleDesc.Count = 1;
+  dst_desc.ArraySize = 1;
+  dst_desc.Usage = D3D11_USAGE_DEFAULT;
+
+  /* If supported, use bind flags for SRV/RTV */
+  hr = ID3D11Device_CheckFormatSupport (device_handle,
+      src_desc.Format, &supported_flags);
+  if (gst_d3d11_result (hr, device)) {
+    if ((supported_flags & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) ==
+        D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) {
+      bind_flags |= D3D11_BIND_SHADER_RESOURCE;
+    }
+
+    if ((supported_flags & D3D11_FORMAT_SUPPORT_RENDER_TARGET) ==
+        D3D11_FORMAT_SUPPORT_RENDER_TARGET) {
+      bind_flags |= D3D11_BIND_RENDER_TARGET;
+    }
+  }
+
+  copy = gst_d3d11_allocator_alloc_internal (alloc, device, &dst_desc);
+  if (!copy) {
+    gst_memory_unmap (mem, &info);
+    gst_d3d11_device_unlock (device);
+
+    GST_WARNING_OBJECT (alloc,
+        "Failed to allocate new d3d11 map memory, try fallback copy");
+
+    return priv->fallback_copy (mem, offset, size);
+  }
+
+  copy_dmem = GST_D3D11_MEMORY_CAST (copy);
+  ID3D11DeviceContext_CopySubresourceRegion (device_context,
+      (ID3D11Resource *) copy_dmem->priv->texture, 0, 0, 0, 0,
+      (ID3D11Resource *) dmem->priv->texture, dmem->priv->subresource_index,
+      NULL);
+  copy->maxsize = copy->size = mem->maxsize;
+  gst_memory_unmap (mem, &info);
+  gst_d3d11_device_unlock (device);
+
+  /* newly allocated memory holds valid image data. We need download this
+   * pixel data into staging memory for CPU access */
+  GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
+
+  return copy;
+}
+
 static void
 gst_d3d11_allocator_init (GstD3D11Allocator * allocator)
 {
   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+  GstD3D11AllocatorPrivate *priv;
+
+  priv = allocator->priv = gst_d3d11_allocator_get_instance_private (allocator);
 
   alloc->mem_type = GST_D3D11_MEMORY_NAME;
   alloc->mem_map_full = gst_d3d11_memory_map_full;
   alloc->mem_unmap_full = gst_d3d11_memory_unmap_full;
   alloc->mem_share = gst_d3d11_memory_share;
-  /* fallback copy */
+
+  /* Store pointer to default mem_copy method for fallback copy */
+  priv->fallback_copy = alloc->mem_copy;
+  alloc->mem_copy = gst_d3d11_memory_copy;
 
   GST_OBJECT_FLAG_SET (alloc, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
 }
index abfb0cd..a80bf7b 100644 (file)
@@ -209,6 +209,8 @@ struct _GstD3D11Allocator
   GstAllocator allocator;
 
   /*< private >*/
+  GstD3D11AllocatorPrivate *priv;
+
   gpointer _gst_reserved[GST_PADDING];
 };