diff --git a/sys/d3d11/gstd3d11_fwd.h b/sys/d3d11/gstd3d11_fwd.h index 8643fd97cd..b3e70e7abc 100644 --- a/sys/d3d11/gstd3d11_fwd.h +++ b/sys/d3d11/gstd3d11_fwd.h @@ -48,12 +48,13 @@ typedef struct _GstD3D11AllocationParams GstD3D11AllocationParams; typedef struct _GstD3D11Memory GstD3D11Memory; typedef struct _GstD3D11Allocator GstD3D11Allocator; typedef struct _GstD3D11AllocatorClass GstD3D11AllocatorClass; -typedef struct _GstD3D11AllocatorPrivate GstD3D11AllocatorPrivate; typedef struct _GstD3D11BufferPool GstD3D11BufferPool; typedef struct _GstD3D11BufferPoolClass GstD3D11BufferPoolClass; typedef struct _GstD3D11BufferPoolPrivate GstD3D11BufferPoolPrivate; +typedef struct _GstD3D11Format GstD3D11Format; + G_END_DECLS #endif /* __GST_D3D11_FWD_H__ */ diff --git a/sys/d3d11/gstd3d11bufferpool.c b/sys/d3d11/gstd3d11bufferpool.c index 7e1058cf48..5e0c68c929 100644 --- a/sys/d3d11/gstd3d11bufferpool.c +++ b/sys/d3d11/gstd3d11bufferpool.c @@ -32,7 +32,9 @@ struct _GstD3D11BufferPoolPrivate { GstD3D11Device *device; GstD3D11Allocator *allocator; - GstCaps *caps; + + /* initial buffer used for calculating buffer size */ + GstBuffer *initial_buffer; gboolean add_videometa; GstD3D11AllocationParams *d3d11_params; @@ -80,9 +82,10 @@ gst_d3d11_buffer_pool_dispose (GObject * object) if (priv->d3d11_params) gst_d3d11_allocation_params_free (priv->d3d11_params); priv->d3d11_params = NULL; + + gst_clear_buffer (&priv->initial_buffer); gst_clear_object (&priv->device); gst_clear_object (&priv->allocator); - gst_clear_caps (&priv->caps); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -90,10 +93,9 @@ gst_d3d11_buffer_pool_dispose (GObject * object) static const gchar ** gst_d3d11_buffer_pool_get_options (GstBufferPool * pool) { - static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, - GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, - NULL - }; + /* NOTE: d3d11 memory does not support alignment */ + static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; + return options; } @@ -105,11 +107,8 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) GstVideoInfo info; GstCaps *caps = NULL; guint min_buffers, max_buffers; - guint max_align, n; GstAllocator *allocator = NULL; - GstAllocationParams alloc_params; gboolean ret = TRUE; - D3D11_TEXTURE2D_DESC *desc; if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers, &max_buffers)) @@ -125,17 +124,14 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height, caps); - if (!gst_buffer_pool_config_get_allocator (config, &allocator, &alloc_params)) + if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) goto wrong_config; - gst_caps_replace (&priv->caps, caps); - - if (priv->allocator) - gst_object_unref (priv->allocator); + gst_clear_buffer (&priv->initial_buffer); + gst_clear_object (&priv->allocator); if (allocator) { if (!GST_IS_D3D11_ALLOCATOR (allocator)) { - gst_object_unref (allocator); goto wrong_allocator; } else { priv->allocator = gst_object_ref (allocator); @@ -152,59 +148,50 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) gst_d3d11_allocation_params_free (priv->d3d11_params); priv->d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config); - if (!priv->d3d11_params) - priv->d3d11_params = gst_d3d11_allocation_params_new (&alloc_params, - &info, NULL); + if (!priv->d3d11_params) { + /* allocate memory with resource format by default */ + priv->d3d11_params = gst_d3d11_allocation_params_new (&info, + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT); + } +#ifndef GST_DISABLE_GST_DEBUG + { + D3D11_TEXTURE2D_DESC *desc; + gint i; + desc = priv->d3d11_params->desc; - desc = &priv->d3d11_params->desc; + GST_LOG_OBJECT (self, "Direct3D11 Allocation params"); + for (i = 0; GST_VIDEO_MAX_PLANES; i++) { + if (desc[i].Format == DXGI_FORMAT_UNKNOWN) + break; + GST_LOG_OBJECT (self, "\t[plane %d] %dx%d, DXGI format %d", + i, desc[i].Width, desc[i].Height, desc[i].Format); + GST_LOG_OBJECT (self, "\t[plane %d] MipLevel %d, ArraySize %d", + i, desc[i].MipLevels, desc[i].ArraySize); + GST_LOG_OBJECT (self, + "\t[plane %d] SampleDesc.Count %d, SampleDesc.Quality %d", + i, desc[i].SampleDesc.Count, desc[i].SampleDesc.Quality); + GST_LOG_OBJECT (self, "\t[plane %d] Usage %d", i, desc[i].Usage); + GST_LOG_OBJECT (self, + "\t[plane %d] BindFlags 0x%x", i, desc[i].BindFlags); + GST_LOG_OBJECT (self, + "\t[plane %d] CPUAccessFlags 0x%x", i, desc[i].CPUAccessFlags); + GST_LOG_OBJECT (self, + "\t[plane %d] MiscFlags 0x%x", i, desc[i].MiscFlags); + } + } +#endif - GST_LOG_OBJECT (self, "Direct3D11 Allocation params"); - GST_LOG_OBJECT (self, "\t%dx%d, DXGI format %d", - desc->Width, desc->Height, desc->Format); - GST_LOG_OBJECT (self, "\tMipLevel %d, ArraySize %d", - desc->MipLevels, desc->ArraySize); - GST_LOG_OBJECT (self, "\tSampleDesc.Count %d, SampleDesc.Quality %d", - desc->SampleDesc.Count, desc->SampleDesc.Quality); - GST_LOG_OBJECT (self, "\tUsage %d", desc->Usage); - GST_LOG_OBJECT (self, "\tBindFlags 0x%x", desc->BindFlags); - GST_LOG_OBJECT (self, "\tCPUAccessFlags 0x%x", desc->CPUAccessFlags); - GST_LOG_OBJECT (self, "\tMiscFlags 0x%x", desc->MiscFlags); + gst_d3d11_buffer_pool_alloc (pool, &priv->initial_buffer, NULL); - max_align = alloc_params.align; - - if (gst_buffer_pool_config_has_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { - priv->add_videometa = TRUE; - - gst_buffer_pool_config_get_video_alignment (config, - &priv->d3d11_params->align); - - for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n) - max_align |= priv->d3d11_params->align.stride_align[n]; - - for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n) - priv->d3d11_params->align.stride_align[n] = max_align; - - gst_video_info_align (&priv->d3d11_params->info, - &priv->d3d11_params->align); - - gst_buffer_pool_config_set_video_alignment (config, - &priv->d3d11_params->align); + if (!priv->initial_buffer) { + GST_ERROR_OBJECT (pool, "Could not create initial buffer"); + return FALSE; } - if (alloc_params.align < max_align) { - GST_WARNING_OBJECT (pool, "allocation params alignment %u is smaller " - "than the max specified video stride alignment %u, fixing", - (guint) alloc_params.align, max_align); - - alloc_params.align = priv->d3d11_params->parent.align = max_align; - gst_buffer_pool_config_set_allocator (config, allocator, &alloc_params); - gst_allocation_params_copy (&alloc_params); - } + self->buffer_size = gst_buffer_get_size (priv->initial_buffer); gst_buffer_pool_config_set_params (config, - caps, GST_VIDEO_INFO_SIZE (&priv->d3d11_params->info), min_buffers, - max_buffers); + caps, self->buffer_size, min_buffers, max_buffers); return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config) && ret; @@ -240,34 +227,71 @@ gst_d3d11_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, GstD3D11BufferPoolPrivate *priv = self->priv; GstMemory *mem; GstBuffer *buf; - GstVideoInfo *info = &priv->d3d11_params->info; + GstD3D11AllocationParams *d3d11_params = priv->d3d11_params; + GstVideoInfo *info = &d3d11_params->info; + gint n_texture = 0; + gint i; + gsize offset[GST_VIDEO_MAX_PLANES] = { 0, }; - mem = gst_d3d11_allocator_alloc (priv->allocator, priv->d3d11_params); + /* consume pre-allocated buffer if any */ + if (G_UNLIKELY (priv->initial_buffer)) { + *buffer = priv->initial_buffer; + priv->initial_buffer = NULL; - if (!mem) { - GST_ERROR_OBJECT (self, "cannot create texture memory"); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } buf = gst_buffer_new (); - gst_buffer_append_memory (buf, mem); + + if ((d3d11_params->flags & GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) == + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) { + + for (n_texture = 0; n_texture < GST_VIDEO_INFO_N_PLANES (info); n_texture++) { + d3d11_params->plane = n_texture; + mem = gst_d3d11_allocator_alloc (priv->allocator, d3d11_params); + if (!mem) + goto error; + + gst_buffer_append_memory (buf, mem); + } + } else { + d3d11_params->plane = 0; + mem = gst_d3d11_allocator_alloc (priv->allocator, priv->d3d11_params); + n_texture++; + + if (!mem) + goto error; + + gst_buffer_append_memory (buf, mem); + } + + /* calculate offset */ + for (i = 0; i < n_texture && i < GST_VIDEO_MAX_PLANES - 1; i++) { + offset[i + 1] = offset[i] + + d3d11_params->stride[i] * GST_VIDEO_INFO_COMP_HEIGHT (info, i); + } if (priv->add_videometa) { - GstD3D11Memory *dmem = (GstD3D11Memory *) mem; - GST_DEBUG_OBJECT (self, "adding GstVideoMeta"); gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info), - dmem->offset, dmem->stride); + offset, d3d11_params->stride); } *buffer = buf; return GST_FLOW_OK; + +error: + gst_buffer_unref (buf); + + GST_ERROR_OBJECT (self, "cannot create texture memory"); + + return GST_FLOW_ERROR; } -GstD3D11BufferPool * +GstBufferPool * gst_d3d11_buffer_pool_new (GstD3D11Device * device) { GstD3D11BufferPool *pool; @@ -281,7 +305,7 @@ gst_d3d11_buffer_pool_new (GstD3D11Device * device) pool->priv->device = gst_object_ref (device); pool->priv->allocator = alloc; - return pool; + return GST_BUFFER_POOL_CAST (pool); } GstD3D11AllocationParams * diff --git a/sys/d3d11/gstd3d11bufferpool.h b/sys/d3d11/gstd3d11bufferpool.h index bb86e16455..e27ccfd1fb 100644 --- a/sys/d3d11/gstd3d11bufferpool.h +++ b/sys/d3d11/gstd3d11bufferpool.h @@ -39,6 +39,9 @@ struct _GstD3D11BufferPool { GstBufferPool parent; + /* re-calculated buffer size based on d3d11 pitch and stride */ + guint buffer_size; + /*< private >*/ GstD3D11BufferPoolPrivate *priv; @@ -55,7 +58,7 @@ struct _GstD3D11BufferPoolClass GType gst_d3d11_buffer_pool_get_type (void); -GstD3D11BufferPool * gst_d3d11_buffer_pool_new (GstD3D11Device *device); +GstBufferPool * gst_d3d11_buffer_pool_new (GstD3D11Device *device); GstD3D11AllocationParams * gst_buffer_pool_config_get_d3d11_allocation_params (GstStructure * config); diff --git a/sys/d3d11/gstd3d11format.c b/sys/d3d11/gstd3d11format.c new file mode 100644 index 0000000000..7d1077e911 --- /dev/null +++ b/sys/d3d11/gstd3d11format.c @@ -0,0 +1,307 @@ +/* GStreamer + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstd3d11format.h" +#include "gstd3d11utils.h" +#include "gstd3d11device.h" + +#ifndef GST_DISABLE_GST_DEBUG +#define GST_CAT_DEFAULT ensure_debug_category() +static GstDebugCategory * +ensure_debug_category (void) +{ + static gsize cat_gonce = 0; + + if (g_once_init_enter (&cat_gonce)) { + gsize cat_done; + + cat_done = (gsize) _gst_debug_category_new ("d3d11format", 0, + "Direct3D11 Format"); + + g_once_init_leave (&cat_gonce, cat_done); + } + + return (GstDebugCategory *) cat_gonce; +} +#else +#define ensure_debug_category() /* NOOP */ +#endif /* GST_DISABLE_GST_DEBUG */ + +/* Following formats were introduced since Windows 8 + * DXGI_FORMAT_AYUV + * DXGI_FORMAT_NV12 + * DXGI_FORMAT_P010 + * ... + */ +static const GstD3D11Format legacy_d3d11_formats[] = { + /* RGB formats */ + {GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM, + {DXGI_FORMAT_B8G8R8A8_UNORM,}}, + {GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, + {DXGI_FORMAT_R8G8B8A8_UNORM,}}, + {GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM, + {DXGI_FORMAT_R10G10B10A2_UNORM,}}, + + /* YUV packed */ + {GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R8G8B8A8_UNORM,}}, + + /* YUV semi-planner */ + {GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}}, + {GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}}, + + /* YUV planner */ + {GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}}, + {GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}}, + + /* LAST */ + {GST_VIDEO_FORMAT_UNKNOWN,}, +}; + +static const GstD3D11Format d3d11_formats[] = { + /* RGB formats */ + {GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM, + {DXGI_FORMAT_B8G8R8A8_UNORM,}}, + {GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, + {DXGI_FORMAT_R8G8B8A8_UNORM,}}, + {GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM, + {DXGI_FORMAT_R10G10B10A2_UNORM,}}, + + /* YUV packed */ + {GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_AYUV, + {DXGI_FORMAT_R8G8B8A8_UNORM,}}, + + /* YUV semi-planner */ + {GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_NV12, + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}}, + {GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_P010, + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}}, + + /* YUV planner */ + {GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}}, + {GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN, + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}}, + + /* LAST */ + {GST_VIDEO_FORMAT_UNKNOWN,}, +}; + +static GstD3D11Format * +get_supported_d3d11_formats (void) +{ + static gsize format_once = 0; + static GstD3D11Format *supported_d3d11_formats = NULL; + + if (g_once_init_enter (&format_once)) { + if (gst_d3d11_is_windows_8_or_greater ()) + supported_d3d11_formats = (GstD3D11Format *) d3d11_formats; + else + supported_d3d11_formats = (GstD3D11Format *) legacy_d3d11_formats; + + g_once_init_leave (&format_once, 1); + } + + return supported_d3d11_formats; +} + +GstVideoFormat +gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format) +{ + gint i; + GstD3D11Format *format_list; + + if (format == DXGI_FORMAT_UNKNOWN) + return GST_VIDEO_FORMAT_UNKNOWN; + + format_list = get_supported_d3d11_formats (); + + for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) { + if (format_list[i].dxgi_format == format) + return format_list[i].format; + } + + return GST_VIDEO_FORMAT_UNKNOWN; +} + +guint +gst_d3d11_dxgi_format_n_planes (DXGI_FORMAT format) +{ + switch (format) { + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16G16_UNORM: + return 1; + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + return 2; + default: + break; + } + + return 0; +} + +gboolean +gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format, guint width, guint height, + guint pitch, gsize offset[GST_VIDEO_MAX_PLANES], + gint stride[GST_VIDEO_MAX_PLANES], gsize * size) +{ + g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE); + + switch (format) { + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16G16_UNORM: + offset[0] = 0; + stride[0] = pitch; + *size = pitch * height; + break; + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + offset[0] = 0; + stride[0] = pitch; + offset[1] = offset[0] + stride[0] * height; + stride[1] = pitch; + *size = offset[1] + stride[1] * GST_ROUND_UP_2 (height / 2); + break; + default: + return FALSE; + } + + GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT + " (dxgi format:%d, %dx%d, Pitch %d)", + *size, format, width, height, pitch); + + return TRUE; +} + +const GstD3D11Format * +gst_d3d11_format_from_gst (GstVideoFormat format) +{ + gint i; + GstD3D11Format *format_list; + + format_list = get_supported_d3d11_formats (); + + for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) { + if (format_list[i].format == format) + return &format_list[i]; + } + + return NULL; +} + +typedef struct +{ + GstCaps *caps; + D3D11_FORMAT_SUPPORT flags; +} SupportCapsData; + +static void +gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device, + SupportCapsData * data) +{ + ID3D11Device *d3d11_device; + HRESULT hr; + gint i; + GValue v_list = G_VALUE_INIT; + GstCaps *supported_caps; + GstD3D11Format *format_list; + + d3d11_device = gst_d3d11_device_get_device_handle (device); + g_value_init (&v_list, GST_TYPE_LIST); + + format_list = get_supported_d3d11_formats (); + + for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) { + UINT format_support = 0; + GstVideoFormat format; + + if (format_list[i].dxgi_format == DXGI_FORMAT_UNKNOWN) + continue; + + format = format_list[i].format; + hr = ID3D11Device_CheckFormatSupport (d3d11_device, + format_list[i].dxgi_format, &format_support); + + if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) { + GValue v_str = G_VALUE_INIT; + g_value_init (&v_str, G_TYPE_STRING); + + GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x", + gst_video_format_to_string (format), data->flags); + g_value_set_string (&v_str, gst_video_format_to_string (format)); + gst_value_list_append_and_take_value (&v_list, &v_str); + } + } + + supported_caps = gst_caps_new_simple ("video/x-raw", + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + gst_caps_set_value (supported_caps, "format", &v_list); + g_value_unset (&v_list); + + data->caps = supported_caps; +} + +/** + * gst_d3d11_device_get_supported_caps: + * @device: a #GstD3DDevice + * @flags: D3D11_FORMAT_SUPPORT flags + * + * Check supported format with given flags + * + * Returns: a #GstCaps representing supported format + */ +GstCaps * +gst_d3d11_device_get_supported_caps (GstD3D11Device * device, + D3D11_FORMAT_SUPPORT flags) +{ + SupportCapsData data; + + g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL); + + data.caps = NULL; + data.flags = flags; + + gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc) + gst_d3d11_device_get_supported_caps_internal, &data); + + return data.caps; +} diff --git a/sys/d3d11/gstd3d11format.h b/sys/d3d11/gstd3d11format.h new file mode 100644 index 0000000000..492c937a48 --- /dev/null +++ b/sys/d3d11/gstd3d11format.h @@ -0,0 +1,63 @@ +/* GStreamer + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_D3D11_FORMAT_H__ +#define __GST_D3D11_FORMAT_H__ + +#include +#include + +#include "gstd3d11_fwd.h" + +#define GST_D3D11_FORMATS \ + "{ BGRA, RGBA, RGB10A2, RGB10A2_LE, VUYA, NV12, P010_10LE, I420, I420_10LE }" + +G_BEGIN_DECLS + +struct _GstD3D11Format +{ + GstVideoFormat format; + + /* direct mapping to dxgi format if applicable */ + DXGI_FORMAT dxgi_format; + + /* formats for texture processing */ + DXGI_FORMAT resource_format[GST_VIDEO_MAX_COMPONENTS]; +}; + +GstVideoFormat gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format); + +guint gst_d3d11_dxgi_format_n_planes (DXGI_FORMAT format); + +gboolean gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format, + guint width, + guint height, + guint pitch, + gsize offset[GST_VIDEO_MAX_PLANES], + gint stride[GST_VIDEO_MAX_PLANES], + gsize *size); + +const GstD3D11Format * gst_d3d11_format_from_gst (GstVideoFormat format); + +GstCaps * gst_d3d11_device_get_supported_caps (GstD3D11Device * device, + D3D11_FORMAT_SUPPORT flags); + +G_END_DECLS + +#endif /* __GST_D3D11_FORMAT_H__ */ diff --git a/sys/d3d11/gstd3d11memory.c b/sys/d3d11/gstd3d11memory.c index 99a47227f7..325a8725d4 100644 --- a/sys/d3d11/gstd3d11memory.c +++ b/sys/d3d11/gstd3d11memory.c @@ -30,33 +30,72 @@ GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug); #define GST_CAT_DEFAULT gst_d3d11_allocator_debug GstD3D11AllocationParams * -gst_d3d11_allocation_params_new (GstAllocationParams * alloc_params, - GstVideoInfo * info, GstVideoAlignment * align) +gst_d3d11_allocation_params_new (GstVideoInfo * info, + GstD3D11AllocationFlags flags) { GstD3D11AllocationParams *ret; + const GstD3D11Format *d3d11_format; + gint i; - g_return_val_if_fail (alloc_params != NULL, NULL); g_return_val_if_fail (info != NULL, NULL); + d3d11_format = gst_d3d11_format_from_gst (GST_VIDEO_INFO_FORMAT (info)); + if (!d3d11_format) { + GST_WARNING ("Couldn't get d3d11 format"); + return NULL; + } + ret = g_new0 (GstD3D11AllocationParams, 1); - memcpy (&ret->info, info, sizeof (GstVideoInfo)); - if (align) { - ret->align = *align; + ret->info = *info; + ret->d3d11_format = d3d11_format; + + /* Usage Flag + * https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_usage + * + * +----------------------------------------------------------+ + * | Resource Usage | Default | Dynamic | Immutable | Staging | + * +----------------+---------+---------+-----------+---------+ + * | GPU-Read | Yes | Yes | Yes | Yes | + * | GPU-Write | Yes | | | Yes | + * | CPU-Read | | | | Yes | + * | CPU-Write | | Yes | | Yes | + * +----------------------------------------------------------+ + */ + + /* If corresponding dxgi format is undefined, use resource format instead */ + if (d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN || + (flags & GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) == + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) { + flags |= GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT; + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) { + g_assert (d3d11_format->resource_format[i] != DXGI_FORMAT_UNKNOWN); + + ret->desc[i].Width = GST_VIDEO_INFO_COMP_WIDTH (info, i); + ret->desc[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i); + ret->desc[i].MipLevels = 1; + ret->desc[i].ArraySize = 1; + ret->desc[i].Format = d3d11_format->resource_format[i]; + ret->desc[i].SampleDesc.Count = 1; + ret->desc[i].SampleDesc.Quality = 0; + ret->desc[i].Usage = D3D11_USAGE_DEFAULT; + /* User must set proper BindFlags and MiscFlags manually */ + } } else { - gst_video_alignment_reset (&ret->align); + g_assert (d3d11_format->dxgi_format != DXGI_FORMAT_UNKNOWN); + + ret->desc[0].Width = GST_VIDEO_INFO_WIDTH (info); + ret->desc[0].Height = GST_VIDEO_INFO_HEIGHT (info); + ret->desc[0].MipLevels = 1; + ret->desc[0].ArraySize = 1; + ret->desc[0].Format = d3d11_format->dxgi_format; + ret->desc[0].SampleDesc.Count = 1; + ret->desc[0].SampleDesc.Quality = 0; + ret->desc[0].Usage = D3D11_USAGE_DEFAULT; } - ret->desc.Width = GST_VIDEO_INFO_WIDTH (info); - ret->desc.Height = GST_VIDEO_INFO_HEIGHT (info); - ret->desc.MipLevels = 1; - ret->desc.ArraySize = 1; - ret->desc.Format = - gst_d3d11_dxgi_format_from_gst (GST_VIDEO_INFO_FORMAT (info)); - ret->desc.SampleDesc.Count = 1; - ret->desc.SampleDesc.Quality = 0; - ret->desc.Usage = D3D11_USAGE_DEFAULT; - /* User must set proper BindFlags and MiscFlags manually */ + ret->flags = flags; return ret; } @@ -88,7 +127,7 @@ G_DEFINE_BOXED_TYPE (GstD3D11AllocationParams, gst_d3d11_allocation_params, G_DEFINE_TYPE (GstD3D11Allocator, gst_d3d11_allocator, GST_TYPE_ALLOCATOR); static inline D3D11_MAP -_gst_map_flags_to_d3d11 (GstMapFlags flags) +gst_map_flags_to_d3d11 (GstMapFlags flags) { if ((flags & GST_MAP_READWRITE) == GST_MAP_READWRITE) return D3D11_MAP_READ_WRITE; @@ -103,7 +142,7 @@ _gst_map_flags_to_d3d11 (GstMapFlags flags) } static ID3D11Texture2D * -_create_staging_texture (GstD3D11Device * device, +create_staging_texture (GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * ref) { D3D11_TEXTURE2D_DESC desc = { 0, }; @@ -120,18 +159,33 @@ _create_staging_texture (GstD3D11Device * device, return gst_d3d11_device_create_texture (device, &desc, NULL); } +typedef struct +{ + ID3D11Resource *dst; + ID3D11Resource *src; +} D3D11CopyTextureData; + +static void +copy_texture (GstD3D11Device * device, D3D11CopyTextureData * data) +{ + ID3D11DeviceContext *device_context = + gst_d3d11_device_get_device_context_handle (device); + + ID3D11DeviceContext_CopySubresourceRegion (device_context, + data->dst, 0, 0, 0, 0, data->src, 0, NULL); +} + typedef struct { GstD3D11Memory *mem; - D3D11_MAP map_flag; + D3D11_MAP map_type; gboolean ret; } D3D11MapData; static void -_map_cpu_access_data (GstD3D11Device * device, gpointer data) +map_cpu_access_data (GstD3D11Device * device, D3D11MapData * map_data) { - D3D11MapData *map_data = (D3D11MapData *) data; GstD3D11Memory *dmem = map_data->mem; HRESULT hr; ID3D11Resource *texture = (ID3D11Resource *) dmem->texture; @@ -139,14 +193,17 @@ _map_cpu_access_data (GstD3D11Device * device, gpointer data) ID3D11DeviceContext *device_context = gst_d3d11_device_get_device_context_handle (device); - ID3D11DeviceContext_CopySubresourceRegion (device_context, - staging, 0, 0, 0, 0, texture, 0, NULL); + if (GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD)) { + ID3D11DeviceContext_CopySubresourceRegion (device_context, + staging, 0, 0, 0, 0, texture, 0, NULL); + } hr = ID3D11DeviceContext_Map (device_context, - staging, 0, map_data->map_flag, 0, &dmem->map); + staging, 0, map_data->map_type, 0, &dmem->map); if (FAILED (hr)) { - GST_ERROR ("Failed to map staging texture (0x%x)", (guint) hr); + GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator, + "Failed to map staging texture (0x%x)", (guint) hr); map_data->ret = FALSE; } @@ -158,64 +215,111 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; - if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) + g_mutex_lock (&dmem->lock); + + if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) { + if (dmem->staging && + GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD)) { + D3D11CopyTextureData data; + + data.dst = (ID3D11Resource *) dmem->texture; + data.src = (ID3D11Resource *) dmem->staging; + + gst_d3d11_device_thread_add (dmem->device, + (GstD3D11DeviceThreadFunc) copy_texture, &data); + } + + GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD); + + if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE) + GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD); + + g_assert (dmem->texture != NULL); + g_mutex_unlock (&dmem->lock); + return dmem->texture; + } if (dmem->cpu_map_count == 0) { D3D11MapData map_data; - GstD3D11Device *device = GST_D3D11_ALLOCATOR (mem->allocator)->device; + + /* Allocate staging texture for CPU access */ + if (!dmem->staging) { + dmem->staging = create_staging_texture (dmem->device, &dmem->desc); + if (!dmem->staging) { + GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture"); + g_mutex_unlock (&dmem->lock); + + return NULL; + } + + /* first memory, always need download to staging */ + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD); + } map_data.mem = dmem; - map_data.map_flag = _gst_map_flags_to_d3d11 (flags); + map_data.map_type = gst_map_flags_to_d3d11 (flags); - gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc) - _map_cpu_access_data, &map_data); + gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc) + map_cpu_access_data, &map_data); + + if (!map_data.ret) { + GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture"); + g_mutex_unlock (&dmem->lock); - if (!map_data.ret) return NULL; + } } if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE) - dmem->need_upload = TRUE; + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD); + + GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD); dmem->cpu_map_count++; + g_mutex_unlock (&dmem->lock); return dmem->map.pData; } static void -_unmap_cpu_access_data (GstD3D11Device * device, gpointer data) +unmap_cpu_access_data (GstD3D11Device * device, gpointer data) { GstD3D11Memory *dmem = (GstD3D11Memory *) data; - ID3D11Resource *texture = (ID3D11Resource *) dmem->texture; ID3D11Resource *staging = (ID3D11Resource *) dmem->staging; ID3D11DeviceContext *device_context = gst_d3d11_device_get_device_context_handle (device); ID3D11DeviceContext_Unmap (device_context, staging, 0); - - if (dmem->need_upload) { - ID3D11DeviceContext_CopySubresourceRegion (device_context, texture, - 0, 0, 0, 0, staging, 0, NULL); - } - dmem->need_upload = FALSE; } static void gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; - GstD3D11Device *device = GST_D3D11_ALLOCATOR (mem->allocator)->device; - if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) + g_mutex_lock (&dmem->lock); + if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) { + if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE) + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD); + + g_mutex_unlock (&dmem->lock); return; + } + + if ((info->flags & GST_MAP_WRITE)) + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD); dmem->cpu_map_count--; - if (dmem->cpu_map_count > 0) + if (dmem->cpu_map_count > 0) { + g_mutex_unlock (&dmem->lock); return; + } - gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc) - _unmap_cpu_access_data, dmem); + gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc) + unmap_cpu_access_data, dmem); + + g_mutex_unlock (&dmem->lock); } static GstMemory * @@ -232,19 +336,30 @@ gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator, gsize size, g_return_val_if_reached (NULL); } +static void +release_texture (GstD3D11Device * device, GstD3D11Memory * mem) +{ + if (mem->texture) + ID3D11Texture2D_Release (mem->texture); + + if (mem->staging) + ID3D11Texture2D_Release (mem->staging); +} + static void gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; - GstD3D11Device *device = GST_D3D11_ALLOCATOR (allocator)->device; + GstD3D11Device *device = dmem->device; - if (dmem->texture) - gst_d3d11_device_release_texture (device, dmem->texture); + if (dmem->texture || dmem->staging) + gst_d3d11_device_thread_add (device, + (GstD3D11DeviceThreadFunc) release_texture, dmem); - if (dmem->staging) - gst_d3d11_device_release_texture (device, dmem->staging); + gst_object_unref (device); + g_mutex_clear (&dmem->lock); - g_slice_free (GstD3D11Memory, dmem); + g_free (dmem); } static void @@ -299,38 +414,40 @@ gst_d3d11_allocator_new (GstD3D11Device * device) return allocator; } -typedef struct _CalculateSizeData +typedef struct { - ID3D11Texture2D *staging; - GstVideoInfo *info; - gsize offset[GST_VIDEO_MAX_PLANES]; + ID3D11Resource *staging; + D3D11_TEXTURE2D_DESC *desc; + gint stride[GST_VIDEO_MAX_PLANES]; gsize size; + gboolean ret; -} CalculateSizeData; +} CalSizeData; static void -_calculate_buffer_size (GstD3D11Device * device, CalculateSizeData * data) +calculate_mem_size (GstD3D11Device * device, CalSizeData * data) { HRESULT hr; D3D11_MAPPED_SUBRESOURCE map; + gsize offset[GST_VIDEO_MAX_PLANES]; ID3D11DeviceContext *device_context = gst_d3d11_device_get_device_context_handle (device); hr = ID3D11DeviceContext_Map (device_context, - (ID3D11Resource *) data->staging, 0, GST_MAP_READWRITE, 0, &map); + data->staging, 0, D3D11_MAP_READ, 0, &map); if (FAILED (hr)) { - GST_ERROR ("Failed to map staging texture (0x%x)", (guint) hr); + GST_ERROR_OBJECT (device, + "Failed to map staging texture (0x%x)", (guint) hr); data->ret = FALSE; - return; } - ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) data->staging, - 0); + data->ret = gst_d3d11_dxgi_format_get_size (data->desc->Format, + data->desc->Width, data->desc->Height, map.RowPitch, + offset, data->stride, &data->size); - data->ret = gst_d3d11_calculate_buffer_size (data->info, - map.RowPitch, data->offset, data->stride, &data->size); + ID3D11DeviceContext_Unmap (device_context, data->staging, 0); } GstMemory * @@ -339,68 +456,81 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator, { GstD3D11Memory *mem; GstD3D11Device *device; - GstAllocationParams *alloc_params; - gsize size, maxsize; ID3D11Texture2D *texture = NULL; ID3D11Texture2D *staging = NULL; - CalculateSizeData data; - gint i; + D3D11_TEXTURE2D_DESC *desc; + gsize *size; + gboolean is_first = FALSE; g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL); g_return_val_if_fail (params != NULL, NULL); device = allocator->device; + desc = ¶ms->desc[params->plane]; + size = ¶ms->size[params->plane]; - texture = gst_d3d11_device_create_texture (device, ¶ms->desc, NULL); + if (*size == 0) + is_first = TRUE; + + texture = gst_d3d11_device_create_texture (device, desc, NULL); if (!texture) { GST_ERROR_OBJECT (allocator, "Couldn't create texture"); goto error; } - staging = _create_staging_texture (device, ¶ms->desc); - if (!staging) { - GST_ERROR_OBJECT (allocator, "Couldn't create staging texture"); - goto error; + /* per plane, allocated staging texture to calculate actual size, + * stride, and offset */ + if (is_first) { + CalSizeData data; + gint num_plane; + gint i; + + staging = create_staging_texture (device, desc); + if (!staging) { + GST_ERROR_OBJECT (allocator, "Couldn't create staging texture"); + goto error; + } + + data.staging = (ID3D11Resource *) staging; + data.desc = desc; + + gst_d3d11_device_thread_add (device, + (GstD3D11DeviceThreadFunc) calculate_mem_size, &data); + + num_plane = gst_d3d11_dxgi_format_n_planes (desc->Format); + + for (i = 0; i < num_plane; i++) { + params->stride[params->plane + i] = data.stride[i]; + } + + *size = data.size; } - /* try map staging texture to get actual stride and size */ - memset (&data, 0, sizeof (CalculateSizeData)); - data.staging = staging; - data.info = ¶ms->info; - gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc) - _calculate_buffer_size, &data); - - if (!data.ret) { - GST_ERROR_OBJECT (allocator, "Couldn't calculate stride"); - goto error; - } - - alloc_params = (GstAllocationParams *) params; - maxsize = size = data.size; - maxsize += alloc_params->prefix + alloc_params->padding; - - mem = g_slice_new0 (GstD3D11Memory); + mem = g_new0 (GstD3D11Memory, 1); gst_memory_init (GST_MEMORY_CAST (mem), - alloc_params->flags, GST_ALLOCATOR_CAST (allocator), NULL, maxsize, - alloc_params->align, 0, size); + 0, GST_ALLOCATOR_CAST (allocator), NULL, *size, 0, 0, *size); - mem->desc = params->desc; + g_mutex_init (&mem->lock); + mem->info = params->info; + mem->plane = params->plane; + mem->desc = *desc; mem->texture = texture; mem->staging = staging; + mem->device = gst_object_ref (device); - for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) { - mem->offset[i] = data.offset[i]; - mem->stride[i] = data.stride[i]; - } + if (staging) + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD); return GST_MEMORY_CAST (mem); error: if (texture) gst_d3d11_device_release_texture (device, texture); + if (staging) - gst_d3d11_device_release_texture (device, staging); + gst_d3d11_device_release_texture (device, texture); + return NULL; } diff --git a/sys/d3d11/gstd3d11memory.h b/sys/d3d11/gstd3d11memory.h index 4ebe8e449d..7ad0bc503d 100644 --- a/sys/d3d11/gstd3d11memory.h +++ b/sys/d3d11/gstd3d11memory.h @@ -25,6 +25,7 @@ #include #include "gstd3d11_fwd.h" +#include "gstd3d11format.h" G_BEGIN_DECLS @@ -52,35 +53,70 @@ G_BEGIN_DECLS */ #define GST_MAP_D3D11 (GST_MAP_FLAG_LAST << 1) +/** + * GstD3D11AllocationFlags: + * GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT: Allocate texture with resource format + * per planes instead of the direct use of DXGI format + */ +typedef enum +{ + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT = (1 << 0), +} GstD3D11AllocationFlags; + +/** + * GstD3D11MemoryTransfer: + * @GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD: the texture needs downloading + * to the staging texture memory + * @GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD: the staging texture needs uploading + * to the texture + */ +typedef enum +{ + GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD = (GST_MEMORY_FLAG_LAST << 0), + GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD = (GST_MEMORY_FLAG_LAST << 1) +} GstD3D11MemoryTransfer; + +struct _GstD3D11AllocationParams +{ + /* Texture description per plane */ + D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES]; + + GstVideoInfo info; + const GstD3D11Format *d3d11_format; + + /* size and stride of staging texture, set by allocator */ + gint stride[GST_VIDEO_MAX_PLANES]; + gsize size[GST_VIDEO_MAX_PLANES]; + + /* Current target plane for allocation */ + guint plane; + + GstD3D11AllocationFlags flags; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + struct _GstD3D11Memory { GstMemory mem; - GstMapFlags map_flags; - gint cpu_map_count; + /*< public > */ + GstD3D11Device *device; ID3D11Texture2D *texture; ID3D11Texture2D *staging; + GstVideoInfo info; + + guint plane; + D3D11_TEXTURE2D_DESC desc; D3D11_MAPPED_SUBRESOURCE map; - gboolean need_upload; - - gsize offset[GST_VIDEO_MAX_PLANES]; - gint stride[GST_VIDEO_MAX_PLANES]; -}; - -struct _GstD3D11AllocationParams -{ - GstAllocationParams parent; - - D3D11_TEXTURE2D_DESC desc; - - GstVideoInfo info; - GstVideoAlignment align; /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + GMutex lock; + gint cpu_map_count; }; struct _GstD3D11Allocator @@ -103,9 +139,8 @@ struct _GstD3D11AllocatorClass GType gst_d3d11_allocation_params_get_type (void); -GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstAllocationParams * alloc_params, - GstVideoInfo * info, - GstVideoAlignment * align); +GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstVideoInfo * info, + GstD3D11AllocationFlags flags); GstD3D11AllocationParams * gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src); @@ -120,7 +155,6 @@ GstMemory * gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator gboolean gst_is_d3d11_memory (GstMemory * mem); - G_END_DECLS #endif /* __GST_D3D11_MEMORY_H__ */ diff --git a/sys/d3d11/gstd3d11utils.c b/sys/d3d11/gstd3d11utils.c index ec0aa48504..8cca47d1f5 100644 --- a/sys/d3d11/gstd3d11utils.c +++ b/sys/d3d11/gstd3d11utils.c @@ -24,6 +24,9 @@ #include "gstd3d11utils.h" #include "gstd3d11device.h" +#include +#include + GST_DEBUG_CATEGORY_STATIC (gst_d3d11_utils_debug); GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); @@ -54,157 +57,6 @@ _init_context_debug (void) #define GST_CAT_DEFAULT _init_d3d11_utils_debug() -static const struct -{ - GstVideoFormat gst_format; - DXGI_FORMAT dxgi_format; -} gst_dxgi_format_map[] = { - /* TODO: add more formats */ - { - GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM}, { - GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM}, { - GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM} -}; - -GstVideoFormat -gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format) -{ - gint i; - - for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) { - if (gst_dxgi_format_map[i].dxgi_format == format) - return gst_dxgi_format_map[i].gst_format; - } - - return GST_VIDEO_FORMAT_UNKNOWN; -} - -DXGI_FORMAT -gst_d3d11_dxgi_format_from_gst (GstVideoFormat format) -{ - gint i; - - for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) { - if (gst_dxgi_format_map[i].gst_format == format) - return gst_dxgi_format_map[i].dxgi_format; - } - - return DXGI_FORMAT_UNKNOWN; -} - -typedef struct -{ - GstCaps *caps; - D3D11_FORMAT_SUPPORT flags; -} SupportCapsData; - -static void -gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device, - SupportCapsData * data) -{ - ID3D11Device *d3d11_device; - HRESULT hr; - gint i; - GValue v_list = G_VALUE_INIT; - GstCaps *supported_caps; - - d3d11_device = gst_d3d11_device_get_device_handle (device); - g_value_init (&v_list, GST_TYPE_LIST); - - for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) { - UINT format_support = 0; - GstVideoFormat format = gst_dxgi_format_map[i].gst_format; - - hr = ID3D11Device_CheckFormatSupport (d3d11_device, - gst_dxgi_format_map[i].dxgi_format, &format_support); - - if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) { - GValue v_str = G_VALUE_INIT; - g_value_init (&v_str, G_TYPE_STRING); - - GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x", - gst_video_format_to_string (format), data->flags); - g_value_set_string (&v_str, gst_video_format_to_string (format)); - gst_value_list_append_and_take_value (&v_list, &v_str); - } - } - - supported_caps = gst_caps_new_simple ("video/x-raw", - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - gst_caps_set_value (supported_caps, "format", &v_list); - g_value_unset (&v_list); - - data->caps = supported_caps; -} - -/** - * gst_d3d11_device_get_supported_caps: - * @device: a #GstD3DDevice - * @flags: D3D11_FORMAT_SUPPORT flags - * - * Check supported format with given flags - * - * Returns: a #GstCaps representing supported format - */ -GstCaps * -gst_d3d11_device_get_supported_caps (GstD3D11Device * device, - D3D11_FORMAT_SUPPORT flags) -{ - SupportCapsData data; - - g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL); - - _init_d3d11_utils_debug (); - _init_context_debug (); - - data.caps = NULL; - data.flags = flags; - - gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc) - gst_d3d11_device_get_supported_caps_internal, &data); - - return data.caps; -} - -gboolean -gst_d3d11_calculate_buffer_size (GstVideoInfo * info, guint pitch, - gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES], - gsize * size) -{ - g_return_val_if_fail (info != NULL, FALSE); - - _init_d3d11_utils_debug (); - _init_context_debug (); - - switch (GST_VIDEO_INFO_FORMAT (info)) { - case GST_VIDEO_FORMAT_BGRA: - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_RGB10A2_LE: - offset[0] = 0; - stride[0] = pitch; - *size = pitch * GST_VIDEO_INFO_HEIGHT (info); - break; - case GST_VIDEO_FORMAT_NV12: - offset[0] = 0; - stride[0] = pitch; - offset[1] = offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (info, 0); - stride[1] = pitch; - *size = offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (info, 1); - break; - default: - return FALSE; - } - - GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT - " (%s %dx%d, Pitch %d)", *size, - gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)), - GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), pitch); - - return TRUE; -} - /** * gst_d3d11_handle_set_context: * @element: a #GstElement @@ -487,3 +339,19 @@ gst_d3d11_ensure_element_data (GstElement * element, gint adapter, return TRUE; } + +gboolean +gst_d3d11_is_windows_8_or_greater (void) +{ + static gsize version_once = 0; + static gboolean ret = FALSE; + + if (g_once_init_enter (&version_once)) { + if (IsWindows8OrGreater ()) + ret = TRUE; + + g_once_init_leave (&version_once, 1); + } + + return ret; +} diff --git a/sys/d3d11/gstd3d11utils.h b/sys/d3d11/gstd3d11utils.h index 541929d4e8..449e3d8e7d 100644 --- a/sys/d3d11/gstd3d11utils.h +++ b/sys/d3d11/gstd3d11utils.h @@ -27,19 +27,6 @@ G_BEGIN_DECLS -GstVideoFormat gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format); - -DXGI_FORMAT gst_d3d11_dxgi_format_from_gst (GstVideoFormat format); - -GstCaps * gst_d3d11_device_get_supported_caps (GstD3D11Device * device, - D3D11_FORMAT_SUPPORT flags); - -gboolean gst_d3d11_calculate_buffer_size (GstVideoInfo * info, - guint pitch, - gsize offset[GST_VIDEO_MAX_PLANES], - gint stride[GST_VIDEO_MAX_PLANES], - gsize *size); - gboolean gst_d3d11_handle_set_context (GstElement * element, GstContext * context, gint adapter, @@ -53,6 +40,8 @@ gboolean gst_d3d11_ensure_element_data (GstElement * element, gint adapter, GstD3D11Device ** device); +gboolean gst_d3d11_is_windows_8_or_greater (void); + G_END_DECLS #endif /* __GST_D3D11_UTILS_H__ */ diff --git a/sys/d3d11/gstd3d11videosink.c b/sys/d3d11/gstd3d11videosink.c index be61036525..225a384b02 100644 --- a/sys/d3d11/gstd3d11videosink.c +++ b/sys/d3d11/gstd3d11videosink.c @@ -246,6 +246,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps) D3D11_TEXTURE2D_DESC desc = { 0, }; ID3D11Texture2D *staging; GError *error = NULL; + const GstD3D11Format *d3d11_format = NULL; GST_DEBUG_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps); @@ -263,6 +264,11 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps) if (!gst_video_info_from_caps (&self->info, caps)) goto invalid_format; + d3d11_format = + gst_d3d11_format_from_gst (GST_VIDEO_INFO_FORMAT (&self->info)); + if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) + goto invalid_format; + video_width = GST_VIDEO_INFO_WIDTH (&self->info); video_height = GST_VIDEO_INFO_HEIGHT (&self->info); video_par_n = GST_VIDEO_INFO_PAR_N (&self->info); @@ -316,8 +322,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps) if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0) goto no_display_size; - self->dxgi_format = - gst_d3d11_dxgi_format_from_gst (GST_VIDEO_INFO_FORMAT (&self->info)); + self->dxgi_format = d3d11_format->dxgi_format; if (!self->window_id) gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (self)); @@ -523,7 +528,7 @@ gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink, GstQuery * query) if (need_pool) { GST_DEBUG_OBJECT (self, "create new pool"); - pool = (GstBufferPool *) gst_d3d11_buffer_pool_new (self->device); + pool = gst_d3d11_buffer_pool_new (self->device); config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, 2, DXGI_MAX_SWAP_CHAIN_BUFFERS); diff --git a/sys/d3d11/meson.build b/sys/d3d11/meson.build index 759a749bb8..5a012ad4bc 100644 --- a/sys/d3d11/meson.build +++ b/sys/d3d11/meson.build @@ -6,6 +6,7 @@ d3d11_sources = [ 'gstd3d11videosink.c', 'gstd3d11window.c', 'plugin.c', + 'gstd3d11format.c', ] have_d3d11 = false