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"
31 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_staging_buffer_pool_debug);
32 #define GST_CAT_DEFAULT gst_d3d11_staging_buffer_pool_debug
34 struct _GstD3D11StagingBufferPoolPrivate
38 D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
39 GstD3D11Allocator *alloc[GST_VIDEO_MAX_PLANES];
40 gint stride[GST_VIDEO_MAX_PLANES];
41 gsize offset[GST_VIDEO_MAX_PLANES];
44 #define gst_d3d11_staging_buffer_pool_parent_class parent_class
45 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11StagingBufferPool,
46 gst_d3d11_staging_buffer_pool, GST_TYPE_BUFFER_POOL);
48 static void gst_d3d11_staging_buffer_pool_dispose (GObject * object);
49 static const gchar **gst_d3d11_staging_buffer_pool_get_options (GstBufferPool *
51 static gboolean gst_d3d11_staging_buffer_pool_set_config (GstBufferPool * pool,
52 GstStructure * config);
53 static GstFlowReturn gst_d3d11_staging_buffer_pool_alloc_buffer (GstBufferPool *
54 pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
55 static gboolean gst_d3d11_staging_buffer_pool_start (GstBufferPool * pool);
56 static gboolean gst_d3d11_staging_buffer_pool_stop (GstBufferPool * pool);
59 gst_d3d11_staging_buffer_pool_class_init (GstD3D11StagingBufferPoolClass *
62 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
63 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);
65 gobject_class->dispose = gst_d3d11_staging_buffer_pool_dispose;
67 bufferpool_class->get_options = gst_d3d11_staging_buffer_pool_get_options;
68 bufferpool_class->set_config = gst_d3d11_staging_buffer_pool_set_config;
69 bufferpool_class->alloc_buffer = gst_d3d11_staging_buffer_pool_alloc_buffer;
70 bufferpool_class->start = gst_d3d11_staging_buffer_pool_start;
71 bufferpool_class->stop = gst_d3d11_staging_buffer_pool_stop;
73 GST_DEBUG_CATEGORY_INIT (gst_d3d11_staging_buffer_pool_debug,
74 "d3d11stagingbufferpool", 0, "d3d11stagingbufferpool object");
78 gst_d3d11_staging_buffer_pool_init (GstD3D11StagingBufferPool * self)
80 self->priv = (GstD3D11StagingBufferPoolPrivate *)
81 gst_d3d11_staging_buffer_pool_get_instance_private (self);
85 gst_d3d11_staging_buffer_pool_clear_allocator (GstD3D11StagingBufferPool * self)
87 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
89 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
91 gst_d3d11_allocator_set_active (priv->alloc[i], FALSE);
92 gst_clear_object (&priv->alloc[i]);
98 gst_d3d11_staging_buffer_pool_dispose (GObject * object)
100 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (object);
102 gst_clear_object (&self->device);
103 gst_d3d11_staging_buffer_pool_clear_allocator (self);
105 G_OBJECT_CLASS (parent_class)->dispose (object);
108 static const gchar **
109 gst_d3d11_staging_buffer_pool_get_options (GstBufferPool * pool)
111 /* NOTE: d3d11 memory does not support alignment */
112 static const gchar *options[] =
113 { GST_BUFFER_POOL_OPTION_VIDEO_META, nullptr };
119 gst_d3d11_staging_buffer_pool_set_config (GstBufferPool * pool,
120 GstStructure * config)
122 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
123 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
125 GstCaps *caps = nullptr;
126 guint min_buffers, max_buffers;
127 D3D11_TEXTURE2D_DESC *desc;
128 const GstD3D11Format *format;
131 if (!gst_buffer_pool_config_get_params (config, &caps, nullptr, &min_buffers,
138 /* now parse the caps from the config */
139 if (!gst_video_info_from_caps (&info, caps))
142 format = gst_d3d11_device_format_from_gst (self->device,
143 GST_VIDEO_INFO_FORMAT (&info));
147 GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
150 gst_d3d11_staging_buffer_pool_clear_allocator (self);
152 memset (priv->stride, 0, sizeof (priv->stride));
153 memset (priv->offset, 0, sizeof (priv->offset));
154 memset (priv->desc, 0, sizeof (priv->desc));
156 if (format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
157 for (guint i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
158 desc = &priv->desc[i];
160 desc->Width = GST_VIDEO_INFO_COMP_WIDTH (&info, i);
161 desc->Height = GST_VIDEO_INFO_COMP_HEIGHT (&info, i);
164 desc->Format = format->resource_format[i];
165 desc->SampleDesc.Count = 1;
166 desc->Usage = D3D11_USAGE_STAGING;
167 desc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
172 desc = &priv->desc[0];
174 width = GST_VIDEO_INFO_WIDTH (&info);
175 height = GST_VIDEO_INFO_HEIGHT (&info);
177 /* resolution of semi-planar formats must be multiple of 2 */
178 switch (format->dxgi_format) {
179 case DXGI_FORMAT_NV12:
180 case DXGI_FORMAT_P010:
181 case DXGI_FORMAT_P016:
182 width = GST_ROUND_UP_2 (width);
183 height = GST_ROUND_UP_2 (height);
190 desc->Height = height;
193 desc->Format = format->dxgi_format;
194 desc->SampleDesc.Count = 1;
195 desc->Usage = D3D11_USAGE_STAGING;
196 desc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
200 for (guint i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
201 GstD3D11Allocator *alloc;
202 GstD3D11PoolAllocator *pool_alloc;
203 GstFlowReturn flow_ret;
204 GstMemory *mem = nullptr;
207 if (priv->desc[i].Format == DXGI_FORMAT_UNKNOWN)
211 (GstD3D11Allocator *) gst_d3d11_pool_allocator_new (self->device,
213 if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
214 GST_ERROR_OBJECT (self, "Failed to activate allocator");
215 gst_object_unref (alloc);
219 pool_alloc = GST_D3D11_POOL_ALLOCATOR (alloc);
220 flow_ret = gst_d3d11_pool_allocator_acquire_memory (pool_alloc, &mem);
221 if (flow_ret != GST_FLOW_OK) {
222 GST_ERROR_OBJECT (self, "Failed to allocate initial memory");
223 gst_d3d11_allocator_set_active (alloc, FALSE);
224 gst_object_unref (alloc);
228 if (!gst_d3d11_memory_get_resource_stride (GST_D3D11_MEMORY_CAST (mem),
229 &stride) || stride < priv->desc[i].Width) {
230 GST_ERROR_OBJECT (self, "Failed to calculate stride");
232 gst_d3d11_allocator_set_active (alloc, FALSE);
233 gst_object_unref (alloc);
234 gst_memory_unref (mem);
239 priv->stride[i] = stride;
240 priv->offset[i] = offset;
243 priv->alloc[i] = alloc;
245 gst_memory_unref (mem);
248 /* single texture semi-planar formats */
249 if (format->dxgi_format != DXGI_FORMAT_UNKNOWN &&
250 GST_VIDEO_INFO_N_PLANES (&info) == 2) {
251 priv->stride[1] = priv->stride[0];
252 priv->offset[1] = priv->stride[0] * priv->desc[0].Height;
255 gst_buffer_pool_config_set_params (config,
256 caps, offset, min_buffers, max_buffers);
260 return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
265 GST_WARNING_OBJECT (pool, "invalid config");
270 GST_WARNING_OBJECT (pool, "no caps in config");
275 GST_WARNING_OBJECT (pool,
276 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
282 gst_d3d11_staging_buffer_pool_fill_buffer (GstD3D11StagingBufferPool * self,
285 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
286 GstFlowReturn ret = GST_FLOW_OK;
288 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
289 GstMemory *mem = nullptr;
290 GstD3D11PoolAllocator *alloc = GST_D3D11_POOL_ALLOCATOR (priv->alloc[i]);
295 ret = gst_d3d11_pool_allocator_acquire_memory (alloc, &mem);
296 if (ret != GST_FLOW_OK) {
297 GST_WARNING_OBJECT (self, "Failed to acquire memory, ret %s",
298 gst_flow_get_name (ret));
302 gst_buffer_append_memory (buf, mem);
309 gst_d3d11_staging_buffer_pool_alloc_buffer (GstBufferPool * pool,
310 GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
312 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
313 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
314 GstVideoInfo *info = &priv->info;
316 GstFlowReturn ret = GST_FLOW_OK;
318 buf = gst_buffer_new ();
319 ret = gst_d3d11_staging_buffer_pool_fill_buffer (self, buf);
320 if (ret != GST_FLOW_OK) {
321 gst_buffer_unref (buf);
325 gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
326 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
327 GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
328 priv->offset, priv->stride);
336 gst_d3d11_staging_buffer_pool_start (GstBufferPool * pool)
338 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
339 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
342 GST_DEBUG_OBJECT (self, "Start");
344 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
345 GstD3D11Allocator *alloc = priv->alloc[i];
350 if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
351 GST_ERROR_OBJECT (self, "Failed to activate allocator");
356 ret = GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
358 GST_ERROR_OBJECT (self, "Failed to start");
360 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
361 GstD3D11Allocator *alloc = priv->alloc[i];
366 gst_d3d11_allocator_set_active (alloc, FALSE);
376 gst_d3d11_staging_buffer_pool_stop (GstBufferPool * pool)
378 GstD3D11StagingBufferPool *self = GST_D3D11_STAGING_BUFFER_POOL (pool);
379 GstD3D11StagingBufferPoolPrivate *priv = self->priv;
381 GST_DEBUG_OBJECT (self, "Stop");
383 for (guint i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
384 GstD3D11Allocator *alloc = priv->alloc[i];
389 if (!gst_d3d11_allocator_set_active (alloc, FALSE)) {
390 GST_ERROR_OBJECT (self, "Failed to deactivate allocator");
395 return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
399 * gst_d3d11_staging_buffer_pool_new:
400 * @device: a #GstD3D11Device to use
402 * Returns: a #GstBufferPool that allocates buffers with #GstD3D11Memory
403 * which hold Direct3D11 staging texture allocated with D3D11_USAGE_STAGING
404 * flag, instead of D3D11_USAGE_DEFAULT. The staging texture can be used for
405 * optimized resource upload/download.
410 gst_d3d11_staging_buffer_pool_new (GstD3D11Device * device)
412 GstD3D11StagingBufferPool *pool;
414 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
416 pool = (GstD3D11StagingBufferPool *)
417 g_object_new (GST_TYPE_D3D11_STAGING_BUFFER_POOL, nullptr);
418 gst_object_ref_sink (pool);
420 pool->device = (GstD3D11Device *) gst_object_ref (device);
422 return GST_BUFFER_POOL_CAST (pool);