2 * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "gstd3d11stagingbufferpool.h"
25 #include "gstd3d11memory.h"
26 #include "gstd3d11device.h"
27 #include "gstd3d11utils.h"
28 #include "gstd3d11_private.h"
32 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_staging_buffer_pool_debug);
33 #define GST_CAT_DEFAULT gst_d3d11_staging_buffer_pool_debug
35 struct _GstD3D11StagingBufferPoolPrivate
39 D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
40 GstD3D11Allocator *alloc[GST_VIDEO_MAX_PLANES];
41 gint stride[GST_VIDEO_MAX_PLANES];
42 gsize offset[GST_VIDEO_MAX_PLANES];
45 #define gst_d3d11_staging_buffer_pool_parent_class parent_class
46 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11StagingBufferPool,
47 gst_d3d11_staging_buffer_pool, GST_TYPE_BUFFER_POOL);
49 static void gst_d3d11_staging_buffer_pool_dispose (GObject * object);
50 static const gchar **gst_d3d11_staging_buffer_pool_get_options (GstBufferPool *
52 static gboolean gst_d3d11_staging_buffer_pool_set_config (GstBufferPool * pool,
53 GstStructure * config);
54 static GstFlowReturn gst_d3d11_staging_buffer_pool_alloc_buffer (GstBufferPool *
55 pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
56 static gboolean gst_d3d11_staging_buffer_pool_start (GstBufferPool * pool);
57 static gboolean gst_d3d11_staging_buffer_pool_stop (GstBufferPool * pool);
60 gst_d3d11_staging_buffer_pool_class_init (GstD3D11StagingBufferPoolClass *
63 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
64 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);
66 gobject_class->dispose = gst_d3d11_staging_buffer_pool_dispose;
68 bufferpool_class->get_options = gst_d3d11_staging_buffer_pool_get_options;
69 bufferpool_class->set_config = gst_d3d11_staging_buffer_pool_set_config;
70 bufferpool_class->alloc_buffer = gst_d3d11_staging_buffer_pool_alloc_buffer;
71 bufferpool_class->start = gst_d3d11_staging_buffer_pool_start;
72 bufferpool_class->stop = gst_d3d11_staging_buffer_pool_stop;
74 GST_DEBUG_CATEGORY_INIT (gst_d3d11_staging_buffer_pool_debug,
75 "d3d11stagingbufferpool", 0, "d3d11stagingbufferpool object");
79 gst_d3d11_staging_buffer_pool_init (GstD3D11StagingBufferPool * self)
81 self->priv = (GstD3D11StagingBufferPoolPrivate *)
82 gst_d3d11_staging_buffer_pool_get_instance_private (self);
86 gst_d3d11_staging_buffer_pool_clear_allocator (GstD3D11StagingBufferPool * self)
88 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
90 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
92 gst_d3d11_allocator_set_active (priv->alloc[i], FALSE);
93 gst_clear_object (&priv->alloc[i]);
99 gst_d3d11_staging_buffer_pool_dispose (GObject * object)
101 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (object);
103 gst_clear_object (&self->device);
104 gst_d3d11_staging_buffer_pool_clear_allocator (self);
106 G_OBJECT_CLASS (parent_class)->dispose (object);
109 static const gchar **
110 gst_d3d11_staging_buffer_pool_get_options (GstBufferPool * pool)
112 /* NOTE: d3d11 memory does not support alignment */
113 static const gchar *options[] =
114 { GST_BUFFER_POOL_OPTION_VIDEO_META, nullptr };
120 gst_d3d11_staging_buffer_pool_set_config (GstBufferPool * pool,
121 GstStructure * config)
123 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
124 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
126 GstCaps *caps = nullptr;
127 guint min_buffers, max_buffers;
128 D3D11_TEXTURE2D_DESC *desc;
129 const GstD3D11Format *format;
132 if (!gst_buffer_pool_config_get_params (config, &caps, nullptr, &min_buffers,
139 /* now parse the caps from the config */
140 if (!gst_video_info_from_caps (&info, caps))
143 format = gst_d3d11_device_format_from_gst (self->device,
144 GST_VIDEO_INFO_FORMAT (&info));
148 GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
151 gst_d3d11_staging_buffer_pool_clear_allocator (self);
153 memset (priv->stride, 0, sizeof (priv->stride));
154 memset (priv->offset, 0, sizeof (priv->offset));
155 memset (priv->desc, 0, sizeof (priv->desc));
157 if (format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
158 for (guint i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
159 desc = &priv->desc[i];
161 desc->Width = GST_VIDEO_INFO_COMP_WIDTH (&info, i);
162 desc->Height = GST_VIDEO_INFO_COMP_HEIGHT (&info, i);
165 desc->Format = format->resource_format[i];
166 desc->SampleDesc.Count = 1;
167 desc->Usage = D3D11_USAGE_STAGING;
168 desc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
173 desc = &priv->desc[0];
175 width = GST_VIDEO_INFO_WIDTH (&info);
176 height = GST_VIDEO_INFO_HEIGHT (&info);
178 /* resolution of semi-planar formats must be multiple of 2 */
179 switch (format->dxgi_format) {
180 case DXGI_FORMAT_NV12:
181 case DXGI_FORMAT_P010:
182 case DXGI_FORMAT_P016:
183 width = GST_ROUND_UP_2 (width);
184 height = GST_ROUND_UP_2 (height);
191 desc->Height = height;
194 desc->Format = format->dxgi_format;
195 desc->SampleDesc.Count = 1;
196 desc->Usage = D3D11_USAGE_STAGING;
197 desc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
201 for (guint i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
202 GstD3D11Allocator *alloc;
203 GstD3D11PoolAllocator *pool_alloc;
204 GstFlowReturn flow_ret;
205 GstMemory *mem = nullptr;
208 if (priv->desc[i].Format == DXGI_FORMAT_UNKNOWN)
212 (GstD3D11Allocator *) gst_d3d11_pool_allocator_new (self->device,
214 if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
215 GST_ERROR_OBJECT (self, "Failed to activate allocator");
216 gst_object_unref (alloc);
220 pool_alloc = GST_D3D11_POOL_ALLOCATOR (alloc);
221 flow_ret = gst_d3d11_pool_allocator_acquire_memory (pool_alloc, &mem);
222 if (flow_ret != GST_FLOW_OK) {
223 GST_ERROR_OBJECT (self, "Failed to allocate initial memory");
224 gst_d3d11_allocator_set_active (alloc, FALSE);
225 gst_object_unref (alloc);
229 if (!gst_d3d11_memory_get_resource_stride (GST_D3D11_MEMORY_CAST (mem),
230 &stride) || stride < priv->desc[i].Width) {
231 GST_ERROR_OBJECT (self, "Failed to calculate stride");
233 gst_d3d11_allocator_set_active (alloc, FALSE);
234 gst_object_unref (alloc);
235 gst_memory_unref (mem);
240 priv->stride[i] = stride;
241 priv->offset[i] = offset;
244 priv->alloc[i] = alloc;
246 gst_memory_unref (mem);
249 /* single texture semi-planar formats */
250 if (format->dxgi_format != DXGI_FORMAT_UNKNOWN &&
251 GST_VIDEO_INFO_N_PLANES (&info) == 2) {
252 priv->stride[1] = priv->stride[0];
253 priv->offset[1] = priv->stride[0] * priv->desc[0].Height;
256 gst_buffer_pool_config_set_params (config,
257 caps, offset, min_buffers, max_buffers);
261 return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
266 GST_WARNING_OBJECT (pool, "invalid config");
271 GST_WARNING_OBJECT (pool, "no caps in config");
276 GST_WARNING_OBJECT (pool,
277 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
283 gst_d3d11_staging_buffer_pool_fill_buffer (GstD3D11StagingBufferPool * self,
286 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
287 GstFlowReturn ret = GST_FLOW_OK;
289 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
290 GstMemory *mem = nullptr;
291 GstD3D11PoolAllocator *alloc = GST_D3D11_POOL_ALLOCATOR (priv->alloc[i]);
296 ret = gst_d3d11_pool_allocator_acquire_memory (alloc, &mem);
297 if (ret != GST_FLOW_OK) {
298 GST_WARNING_OBJECT (self, "Failed to acquire memory, ret %s",
299 gst_flow_get_name (ret));
303 gst_buffer_append_memory (buf, mem);
310 gst_d3d11_staging_buffer_pool_alloc_buffer (GstBufferPool * pool,
311 GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
313 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
314 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
315 GstVideoInfo *info = &priv->info;
317 GstFlowReturn ret = GST_FLOW_OK;
319 buf = gst_buffer_new ();
320 ret = gst_d3d11_staging_buffer_pool_fill_buffer (self, buf);
321 if (ret != GST_FLOW_OK) {
322 gst_buffer_unref (buf);
326 gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
327 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
328 GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
329 priv->offset, priv->stride);
337 gst_d3d11_staging_buffer_pool_start (GstBufferPool * pool)
339 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
340 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
343 GST_DEBUG_OBJECT (self, "Start");
345 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
346 GstD3D11Allocator *alloc = priv->alloc[i];
351 if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
352 GST_ERROR_OBJECT (self, "Failed to activate allocator");
357 ret = GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
359 GST_ERROR_OBJECT (self, "Failed to start");
361 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
362 GstD3D11Allocator *alloc = priv->alloc[i];
367 gst_d3d11_allocator_set_active (alloc, FALSE);
377 gst_d3d11_staging_buffer_pool_stop (GstBufferPool * pool)
379 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
380 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
382 GST_DEBUG_OBJECT (self, "Stop");
384 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
385 GstD3D11Allocator *alloc = priv->alloc[i];
390 if (!gst_d3d11_allocator_set_active (alloc, FALSE)) {
391 GST_ERROR_OBJECT (self, "Failed to deactivate allocator");
396 return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
400 * gst_d3d11_staging_buffer_pool_new:
401 * @device: a #GstD3D11Device to use
403 * Returns: a #GstBufferPool that allocates buffers with #GstD3D11Memory
404 * which hold Direct3D11 staging texture allocated with D3D11_USAGE_STAGING
405 * flag, instead of D3D11_USAGE_DEFAULT. The staging texture can be used for
406 * optimized resource upload/download.
411 gst_d3d11_staging_buffer_pool_new (GstD3D11Device * device)
413 GstD3D11StagingBufferPool *pool;
415 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
417 pool = (GstD3D11StagingBufferPool *)
418 g_object_new (GST_TYPE_D3D11_STAGING_BUFFER_POOL, nullptr);
419 gst_object_ref_sink (pool);
421 pool->device = (GstD3D11Device *) gst_object_ref (device);
423 return GST_BUFFER_POOL_CAST (pool);