From ddd13fc7c061a9873b181d0de32aaf9546e7d0af Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 30 Nov 2019 20:26:26 +0900 Subject: [PATCH] d3d11: Add support for D3D11_USAGE_DYNAMIC D3D11 dynamic texture is a special memory type, which is mainly used for frequent CPU write access to the texture. For now, this texture type does not support gst_memory_{map,unmap} --- sys/d3d11/gstd3d11bufferpool.c | 2 +- sys/d3d11/gstd3d11colorconvert.c | 63 ++++++++++---- sys/d3d11/gstd3d11memory.c | 76 +++++++++++++---- sys/d3d11/gstd3d11memory.h | 4 +- sys/d3d11/gstd3d11upload.c | 137 ++++++++++++++++++++++++++++++- sys/d3d11/gstd3d11utils.c | 81 ++++++++++++++++++ sys/d3d11/gstd3d11utils.h | 13 +++ sys/d3d11/gstd3d11videosink.c | 33 ++++++-- 8 files changed, 361 insertions(+), 48 deletions(-) diff --git a/sys/d3d11/gstd3d11bufferpool.c b/sys/d3d11/gstd3d11bufferpool.c index 5e0c68c929..123ef8f9c0 100644 --- a/sys/d3d11/gstd3d11bufferpool.c +++ b/sys/d3d11/gstd3d11bufferpool.c @@ -151,7 +151,7 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) 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); + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, D3D11_USAGE_DEFAULT, 0); } #ifndef GST_DISABLE_GST_DEBUG { diff --git a/sys/d3d11/gstd3d11colorconvert.c b/sys/d3d11/gstd3d11colorconvert.c index 6c61d32324..b5b97e1327 100644 --- a/sys/d3d11/gstd3d11colorconvert.c +++ b/sys/d3d11/gstd3d11colorconvert.c @@ -261,6 +261,8 @@ static GstFlowReturn gst_d3d11_color_convert_transform (GstBaseTransform * static gboolean gst_d3d11_color_convert_set_info (GstD3D11BaseFilter * filter, GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info); +static gboolean gst_d3d11_color_convert_query (GstBaseTransform * trans, + GstPadDirection direction, GstQuery * query); /* copies the given caps */ static GstCaps * @@ -458,6 +460,7 @@ gst_d3d11_color_convert_class_init (GstD3D11ColorConvertClass * klass) trans_class->transform = GST_DEBUG_FUNCPTR (gst_d3d11_color_convert_transform); trans_class->start = GST_DEBUG_FUNCPTR (gst_d3d11_color_convert_start); + trans_class->query = GST_DEBUG_FUNCPTR (gst_d3d11_color_convert_query); bfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_d3d11_color_convert_set_info); @@ -740,13 +743,15 @@ gst_d3d11_color_convert_propose_allocation (GstBaseTransform * trans, gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config); - if (!d3d11_params) + if (!d3d11_params) { d3d11_params = gst_d3d11_allocation_params_new (&info, - GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT); - - /* Set bind flag */ - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) { - d3d11_params->desc[i].BindFlags |= D3D11_BIND_SHADER_RESOURCE; + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE); + } else { + /* Set bind flag */ + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) { + d3d11_params->desc[i].BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } } gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params); @@ -817,14 +822,16 @@ gst_d3d11_color_convert_decide_allocation (GstBaseTransform * trans, gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config); - if (!d3d11_params) + if (!d3d11_params) { d3d11_params = gst_d3d11_allocation_params_new (&info, - GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT); - - /* Set bind flag */ - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) { - d3d11_params->desc[i].BindFlags |= - (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, D3D11_USAGE_DEFAULT, + D3D11_BIND_RENDER_TARGET); + } else { + /* Set bind flag */ + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) { + d3d11_params->desc[i].BindFlags |= + (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + } } gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params); @@ -868,6 +875,26 @@ gst_d3d11_color_convert_start (GstBaseTransform * trans) return TRUE; } +static gboolean +gst_d3d11_color_convert_query (GstBaseTransform * trans, + GstPadDirection direction, GstQuery * query) +{ + if (gst_query_is_d3d11_usage (query) && direction == GST_PAD_SINK) { + D3D11_USAGE usage = D3D11_USAGE_DEFAULT; + + gst_query_parse_d3d11_usage (query, &usage); + if (usage == D3D11_USAGE_DEFAULT || usage == D3D11_USAGE_DYNAMIC) + gst_query_set_d3d11_usage_result (query, TRUE); + else + gst_query_set_d3d11_usage_result (query, FALSE); + + return TRUE; + } + + return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction, + query); +} + /* from video-converter.c */ typedef struct { @@ -1897,11 +1924,13 @@ do_convert (GstD3D11Device * device, DoConvertData * data) g_assert (gst_is_d3d11_memory (mem)); - /* map to transfer pending staging data if any */ - gst_memory_map (mem, &info, GST_MAP_READ | GST_MAP_D3D11); - gst_memory_unmap (mem, &info); - d3d11_mem = (GstD3D11Memory *) mem; + /* map to transfer pending staging data if any */ + if (d3d11_mem->desc.Usage == D3D11_USAGE_DEFAULT) { + gst_memory_map (mem, &info, GST_MAP_READ | GST_MAP_D3D11); + gst_memory_unmap (mem, &info); + } + if (gst_d3d11_memory_ensure_shader_resource_view (mem)) { for (j = 0; j < d3d11_mem->num_shader_resource_views; j++) { resource_view[view_index] = d3d11_mem->shader_resource_view[j]; diff --git a/sys/d3d11/gstd3d11memory.c b/sys/d3d11/gstd3d11memory.c index 8edeae9dde..32f743627f 100644 --- a/sys/d3d11/gstd3d11memory.c +++ b/sys/d3d11/gstd3d11memory.c @@ -31,11 +31,12 @@ GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug); GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstVideoInfo * info, - GstD3D11AllocationFlags flags) + GstD3D11AllocationFlags flags, D3D11_USAGE usage, gint bind_flags) { GstD3D11AllocationParams *ret; const GstD3D11Format *d3d11_format; gint i; + gint cpu_access_flags; g_return_val_if_fail (info != NULL, NULL); @@ -45,6 +46,15 @@ gst_d3d11_allocation_params_new (GstVideoInfo * info, return NULL; } + if (usage == D3D11_USAGE_DEFAULT) { + cpu_access_flags = 0; + } else if (usage == D3D11_USAGE_DYNAMIC) { + cpu_access_flags = D3D11_CPU_ACCESS_WRITE; + } else { + GST_FIXME ("Neither default nor dynamic usage"); + return NULL; + } + ret = g_new0 (GstD3D11AllocationParams, 1); ret->info = *info; @@ -79,8 +89,9 @@ gst_d3d11_allocation_params_new (GstVideoInfo * info, 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 */ + ret->desc[i].Usage = usage; + ret->desc[i].BindFlags = bind_flags; + ret->desc[i].CPUAccessFlags = cpu_access_flags; } } else { g_assert (d3d11_format->dxgi_format != DXGI_FORMAT_UNKNOWN); @@ -92,7 +103,9 @@ gst_d3d11_allocation_params_new (GstVideoInfo * info, 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[0].Usage = usage; + ret->desc[0].BindFlags = bind_flags; + ret->desc[0].CPUAccessFlags = cpu_access_flags; } ret->flags = flags; @@ -242,8 +255,13 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; - g_mutex_lock (&dmem->lock); + if (dmem->desc.Usage == D3D11_USAGE_DYNAMIC) { + GST_FIXME_OBJECT (mem->allocator, + "D3D11_USAGE_DYNAMIC shouldn't be used with gst_memory_map"); + return NULL; + } + 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)) { @@ -325,6 +343,12 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; + if (dmem->desc.Usage == D3D11_USAGE_DYNAMIC) { + GST_FIXME_OBJECT (mem->allocator, + "D3D11_USAGE_DYNAMIC shouldn't be used with gst_memory_unmap"); + return; + } + g_mutex_lock (&dmem->lock); if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) { if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE) @@ -454,8 +478,9 @@ gst_d3d11_allocator_new (GstD3D11Device * device) typedef struct { - ID3D11Resource *staging; + ID3D11Resource *texture; D3D11_TEXTURE2D_DESC *desc; + D3D11_MAP map_mode; gint stride[GST_VIDEO_MAX_PLANES]; gsize size; @@ -473,11 +498,10 @@ calculate_mem_size (GstD3D11Device * device, CalSizeData * data) gst_d3d11_device_get_device_context_handle (device); hr = ID3D11DeviceContext_Map (device_context, - data->staging, 0, D3D11_MAP_READ, 0, &map); + data->texture, 0, data->map_mode, 0, &map); if (FAILED (hr)) { - GST_ERROR_OBJECT (device, - "Failed to map staging texture (0x%x)", (guint) hr); + GST_ERROR_OBJECT (device, "Failed to map texture (0x%x)", (guint) hr); data->ret = FALSE; } @@ -485,7 +509,7 @@ calculate_mem_size (GstD3D11Device * device, CalSizeData * data) data->desc->Width, data->desc->Height, map.RowPitch, offset, data->stride, &data->size); - ID3D11DeviceContext_Unmap (device_context, data->staging, 0); + ID3D11DeviceContext_Unmap (device_context, data->texture, 0); } static void @@ -649,6 +673,7 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator, D3D11_TEXTURE2D_DESC *desc; gsize *size; gboolean is_first = FALSE; + GstMemoryFlags memory_flags; g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL); g_return_val_if_fail (params != NULL, NULL); @@ -657,6 +682,16 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator, desc = ¶ms->desc[params->plane]; size = ¶ms->size[params->plane]; + if (desc->Usage == D3D11_USAGE_DEFAULT) { + memory_flags = 0; + } else if (desc->Usage == D3D11_USAGE_DYNAMIC) { + /* FIXME: how we can make D3D11_USAGE_DYNAMIC work with GST_MAP_READWRITE ? */ + memory_flags = GST_MEMORY_FLAG_NOT_MAPPABLE; + } else { + GST_FIXME_OBJECT (allocator, "Cannot support usage %d", desc->Usage); + return NULL; + } + if (*size == 0) is_first = TRUE; @@ -673,13 +708,22 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator, gint num_plane; gint i; - staging = create_staging_texture (device, desc); - if (!staging) { - GST_ERROR_OBJECT (allocator, "Couldn't create staging texture"); - goto error; + if (desc->Usage == D3D11_USAGE_DEFAULT) { + staging = create_staging_texture (device, desc); + if (!staging) { + GST_ERROR_OBJECT (allocator, "Couldn't create staging texture"); + goto error; + } + + data.texture = (ID3D11Resource *) staging; + data.map_mode = D3D11_MAP_READ; + } else if (desc->Usage == D3D11_USAGE_DYNAMIC) { + data.texture = (ID3D11Resource *) texture; + data.map_mode = D3D11_MAP_WRITE_DISCARD; + } else { + g_assert_not_reached (); } - data.staging = (ID3D11Resource *) staging; data.desc = desc; gst_d3d11_device_thread_add (device, @@ -697,7 +741,7 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator, mem = g_new0 (GstD3D11Memory, 1); gst_memory_init (GST_MEMORY_CAST (mem), - 0, GST_ALLOCATOR_CAST (allocator), NULL, *size, 0, 0, *size); + memory_flags, GST_ALLOCATOR_CAST (allocator), NULL, *size, 0, 0, *size); g_mutex_init (&mem->lock); mem->info = params->info; diff --git a/sys/d3d11/gstd3d11memory.h b/sys/d3d11/gstd3d11memory.h index 56616ca90b..e2a67acfbe 100644 --- a/sys/d3d11/gstd3d11memory.h +++ b/sys/d3d11/gstd3d11memory.h @@ -146,7 +146,9 @@ struct _GstD3D11AllocatorClass GType gst_d3d11_allocation_params_get_type (void); GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstVideoInfo * info, - GstD3D11AllocationFlags flags); + GstD3D11AllocationFlags flags, + D3D11_USAGE usage, + gint bind_flags); GstD3D11AllocationParams * gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src); diff --git a/sys/d3d11/gstd3d11upload.c b/sys/d3d11/gstd3d11upload.c index e2bf4ce44c..f3d7bf2239 100644 --- a/sys/d3d11/gstd3d11upload.c +++ b/sys/d3d11/gstd3d11upload.c @@ -25,6 +25,9 @@ #include "gstd3d11memory.h" #include "gstd3d11device.h" #include "gstd3d11bufferpool.h" +#include "gstd3d11utils.h" + +#include GST_DEBUG_CATEGORY_STATIC (gst_d3d11_upload_debug); #define GST_CAT_DEFAULT gst_d3d11_upload_debug @@ -224,12 +227,16 @@ gst_d3d11_upload_decide_allocation (GstBaseTransform * trans, GstQuery * query) guint size, min, max; GstStructure *config; gboolean update_pool = FALSE; + GstVideoInfo vinfo; + gint i; gst_query_parse_allocation (query, &outcaps, NULL); if (!outcaps) return FALSE; + gst_video_info_from_caps (&vinfo, outcaps); + if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); if (pool && !GST_IS_D3D11_BUFFER_POOL (pool)) { @@ -239,8 +246,6 @@ gst_d3d11_upload_decide_allocation (GstBaseTransform * trans, GstQuery * query) update_pool = TRUE; } else { - GstVideoInfo vinfo; - gst_video_info_from_caps (&vinfo, outcaps); size = GST_VIDEO_INFO_SIZE (&vinfo); min = max = 0; } @@ -254,6 +259,45 @@ gst_d3d11_upload_decide_allocation (GstBaseTransform * trans, GstQuery * query) config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_config_set_params (config, outcaps, size, min, max); + + { + GstQuery *usage_query; + gboolean can_dynamic = FALSE; + + usage_query = gst_query_new_d3d11_usage (D3D11_USAGE_DYNAMIC); + gst_pad_peer_query (GST_BASE_TRANSFORM_SRC_PAD (trans), usage_query); + gst_query_parse_d3d11_usage_result (usage_query, &can_dynamic); + gst_query_unref (usage_query); + + if (can_dynamic) { + GstD3D11AllocationParams *d3d11_params; + + GST_DEBUG_OBJECT (trans, "downstream support dynamic usage"); + + d3d11_params = + gst_buffer_pool_config_get_d3d11_allocation_params (config); + if (!d3d11_params) { + /* dynamic usage should have at least one bind flag. + * but followings are not allowed in this case + * D3D11_BIND_STREAM_OUTPUT + * D3D11_BIND_RENDER_TARGET + * D3D11_BIND_DEPTH_STENCIL + * D3D11_BIND_UNORDERED_ACCESS */ + d3d11_params = gst_d3d11_allocation_params_new (&vinfo, + GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, + D3D11_USAGE_DYNAMIC, D3D11_BIND_SHADER_RESOURCE); + } else { + for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) { + d3d11_params->desc[i].Usage = D3D11_USAGE_DYNAMIC; + d3d11_params->desc[i].CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + } + + gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params); + gst_d3d11_allocation_params_free (d3d11_params); + } + } + gst_buffer_pool_set_config (pool, config); /* update size with calculated one */ @@ -278,6 +322,82 @@ typedef struct GstFlowReturn ret; } UploadTransformData; +static void +upload_transform_dynamic (GstD3D11Device * device, UploadTransformData * data) +{ + GstVideoFrame in_frame; + GstD3D11BaseFilter *filter = data->filter; + gint i, j, k; + ID3D11DeviceContext *device_context = + gst_d3d11_device_get_device_context_handle (device); + + data->ret = GST_FLOW_OK; + + if (!gst_video_frame_map (&in_frame, &filter->in_info, data->inbuf, + GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) + goto invalid_buffer; + + for (i = 0, j = 0; i < gst_buffer_n_memory (data->outbuf); i++) { + GstD3D11Memory *dmem = + (GstD3D11Memory *) gst_buffer_peek_memory (data->outbuf, i); + D3D11_MAPPED_SUBRESOURCE map; + HRESULT hr; + D3D11_TEXTURE2D_DESC *desc = &dmem->desc; + gsize offset[GST_VIDEO_MAX_PLANES]; + gint stride[GST_VIDEO_MAX_PLANES]; + gsize dummy; + + hr = ID3D11DeviceContext_Map (device_context, + (ID3D11Resource *) dmem->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + + if (FAILED (hr)) { + GST_ERROR_OBJECT (filter, + "Failed to map staging texture (0x%x)", (guint) hr); + data->ret = GST_FLOW_ERROR; + goto done; + } + + gst_d3d11_dxgi_format_get_size (desc->Format, desc->Width, desc->Height, + map.RowPitch, offset, stride, &dummy); + + for (k = 0; k < gst_d3d11_dxgi_format_n_planes (dmem->desc.Format); k++) { + gint h, width; + guint8 *dst, *src; + + dst = (guint8 *) map.pData + offset[k]; + src = GST_VIDEO_FRAME_PLANE_DATA (&in_frame, j); + width = GST_VIDEO_FRAME_COMP_WIDTH (&in_frame, j) * + GST_VIDEO_FRAME_COMP_PSTRIDE (&in_frame, j); + + for (h = 0; h < GST_VIDEO_FRAME_COMP_HEIGHT (&in_frame, j); h++) { + memcpy (dst, src, width); + dst += stride[k]; + src += GST_VIDEO_FRAME_PLANE_STRIDE (&in_frame, j); + } + + j++; + } + + ID3D11DeviceContext_Unmap (device_context, + (ID3D11Resource *) dmem->texture, 0); + } + +done: + gst_video_frame_unmap (&in_frame); + + data->ret = GST_FLOW_OK; + return; + + /* ERRORS */ +invalid_buffer: + { + GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), + ("invalid video buffer received")); + data->ret = GST_FLOW_ERROR; + return; + } +} + static void upload_transform (GstD3D11Device * device, UploadTransformData * data) { @@ -327,11 +447,15 @@ gst_d3d11_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf, GstMemory *mem; GstD3D11Device *device; UploadTransformData data; + gboolean to_dynamic = FALSE; mem = gst_buffer_peek_memory (outbuf, 0); if (gst_is_d3d11_memory (mem)) { GstD3D11Memory *dmem = (GstD3D11Memory *) mem; device = dmem->device; + + if (dmem->desc.Usage == D3D11_USAGE_DYNAMIC) + to_dynamic = TRUE; } else { device = filter->device; } @@ -341,8 +465,13 @@ gst_d3d11_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf, data.outbuf = outbuf; data.ret = GST_FLOW_OK; - gst_d3d11_device_thread_add (device, - (GstD3D11DeviceThreadFunc) upload_transform, &data); + if (to_dynamic) { + gst_d3d11_device_thread_add (device, + (GstD3D11DeviceThreadFunc) upload_transform_dynamic, &data); + } else { + gst_d3d11_device_thread_add (device, + (GstD3D11DeviceThreadFunc) upload_transform, &data); + } return data.ret; } diff --git a/sys/d3d11/gstd3d11utils.c b/sys/d3d11/gstd3d11utils.c index 8cca47d1f5..99cc92b806 100644 --- a/sys/d3d11/gstd3d11utils.c +++ b/sys/d3d11/gstd3d11utils.c @@ -355,3 +355,84 @@ gst_d3d11_is_windows_8_or_greater (void) return ret; } + +GstQuery * +gst_query_new_d3d11_usage (D3D11_USAGE usage) +{ + GstQuery *query; + GstStructure *structure; + + structure = gst_structure_new ("GstQueryD3D11Usage", + "usage", G_TYPE_INT, usage, "result", G_TYPE_BOOLEAN, FALSE, NULL); + query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); + + return query; +} + +void +gst_query_parse_d3d11_usage (GstQuery * query, D3D11_USAGE * usage) +{ + const GstStructure *structure; + + g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CUSTOM); + + if (!gst_query_is_d3d11_usage (query)) + return; + + structure = gst_query_get_structure (query); + + gst_structure_get (structure, "usage", G_TYPE_INT, usage, NULL); +} + +void +gst_query_set_d3d11_usage_result (GstQuery * query, gboolean result) +{ + GstStructure *structure; + const gchar *name; + + g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CUSTOM); + g_return_if_fail (gst_query_is_writable (query)); + + structure = gst_query_writable_structure (query); + name = gst_structure_get_name (structure); + + g_return_if_fail (g_strcmp0 (name, "GstQueryD3D11Usage") == 0); + gst_structure_set (structure, "result", G_TYPE_BOOLEAN, result, NULL); +} + +void +gst_query_parse_d3d11_usage_result (GstQuery * query, gboolean * result) +{ + const GstStructure *structure; + const gchar *name; + + g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CUSTOM); + g_return_if_fail (gst_query_is_writable (query)); + g_return_if_fail (result != NULL); + + structure = gst_query_get_structure (query); + name = gst_structure_get_name (structure); + + g_return_if_fail (g_strcmp0 (name, "GstQueryD3D11Usage") == 0); + + gst_structure_get (structure, "result", G_TYPE_BOOLEAN, result, NULL); +} + +gboolean +gst_query_is_d3d11_usage (GstQuery * query) +{ + const GstStructure *structure; + + g_return_val_if_fail (GST_IS_QUERY (query), FALSE); + + if (GST_QUERY_TYPE (query) != GST_QUERY_CUSTOM) + return FALSE; + + structure = gst_query_get_structure (query); + + if (!structure || + g_strcmp0 (gst_structure_get_name (structure), "GstQueryD3D11Usage")) + return FALSE; + + return TRUE; +} diff --git a/sys/d3d11/gstd3d11utils.h b/sys/d3d11/gstd3d11utils.h index 449e3d8e7d..6a13e009a0 100644 --- a/sys/d3d11/gstd3d11utils.h +++ b/sys/d3d11/gstd3d11utils.h @@ -42,6 +42,19 @@ gboolean gst_d3d11_ensure_element_data (GstElement * element, gboolean gst_d3d11_is_windows_8_or_greater (void); +GstQuery * gst_query_new_d3d11_usage (D3D11_USAGE usage); + +void gst_query_parse_d3d11_usage (GstQuery * query, + D3D11_USAGE *usage); + +void gst_query_set_d3d11_usage_result (GstQuery * query, + gboolean result); + +void gst_query_parse_d3d11_usage_result (GstQuery * query, + gboolean * result); + +gboolean gst_query_is_d3d11_usage (GstQuery * query); + G_END_DECLS #endif /* __GST_D3D11_UTILS_H__ */ diff --git a/sys/d3d11/gstd3d11videosink.c b/sys/d3d11/gstd3d11videosink.c index da88d32fb4..5b62fd1be0 100644 --- a/sys/d3d11/gstd3d11videosink.c +++ b/sys/d3d11/gstd3d11videosink.c @@ -584,6 +584,19 @@ gst_d3d11_video_sink_query (GstBaseSink * sink, GstQuery * query) return TRUE; } break; + case GST_QUERY_CUSTOM: + if (gst_query_is_d3d11_usage (query)) { + D3D11_USAGE usage = D3D11_USAGE_DEFAULT; + + gst_query_parse_d3d11_usage (query, &usage); + if (usage == D3D11_USAGE_DEFAULT || usage == D3D11_USAGE_DYNAMIC) + gst_query_set_d3d11_usage_result (query, TRUE); + else + gst_query_set_d3d11_usage_result (query, FALSE); + + return TRUE; + } + break; default: break; } @@ -657,23 +670,28 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf) ID3D11Texture2D *texture; GstMapInfo map; GstFlowReturn ret; - gboolean need_unmap = FALSE; GstMemory *mem; GstVideoRectangle rect = { 0, }; GstVideoCropMeta *crop; if (gst_buffer_n_memory (buf) == 1 && (mem = gst_buffer_peek_memory (buf, 0)) && gst_memory_is_type (mem, GST_D3D11_MEMORY_NAME)) { + GstD3D11Memory *dmem = (GstD3D11Memory *) mem; + /* If this buffer has been allocated using our buffer management we simply put the ximage which is in the PRIVATE pointer */ GST_TRACE_OBJECT (self, "buffer %p from our pool, writing directly", buf); - if (!gst_memory_map (mem, &map, (GST_MAP_READ | GST_MAP_D3D11))) { - GST_ERROR_OBJECT (self, "cannot map d3d11 memory"); - return GST_FLOW_ERROR; + + if (dmem->desc.Usage == D3D11_USAGE_DEFAULT) { + if (!gst_memory_map (mem, &map, (GST_MAP_READ | GST_MAP_D3D11))) { + GST_ERROR_OBJECT (self, "cannot map d3d11 memory"); + return GST_FLOW_ERROR; + } + + gst_memory_unmap (mem, &map); } - texture = (ID3D11Texture2D *) map.data; - need_unmap = TRUE; + texture = dmem->texture; } else { if (!gst_video_frame_map (&frame, &self->info, buf, GST_MAP_READ)) { GST_ERROR_OBJECT (self, "cannot map video frame"); @@ -714,9 +732,6 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf) ret = gst_d3d11_window_render (self->window, texture, &rect); - if (need_unmap) - gst_memory_unmap (mem, &map); - if (ret == GST_D3D11_WINDOW_FLOW_CLOSED) { GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, ("Output window was closed"), (NULL));