From 800961cf289c85976f3d3318e1cd763b516e53ce Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 19 Jul 2024 01:14:20 +0900 Subject: [PATCH] d3d12decoder: Add support for d3d11 output again Although d3d12download supports d3d12 to d3d11 texture copy, this feature might be useful if an application is not ready to d3d12 support and it expects output type of decodebin(3) is d3d11. Part-of: --- .../sys/d3d12/gstd3d12av1dec.cpp | 20 +- .../sys/d3d12/gstd3d12av1dec.h | 3 +- .../sys/d3d12/gstd3d12decoder.cpp | 581 +++++++++++++----- .../sys/d3d12/gstd3d12decoder.h | 14 +- .../sys/d3d12/gstd3d12h264dec.cpp | 24 +- .../sys/d3d12/gstd3d12h264dec.h | 3 +- .../sys/d3d12/gstd3d12h265dec.cpp | 20 +- .../sys/d3d12/gstd3d12h265dec.h | 3 +- .../sys/d3d12/gstd3d12mpeg2dec.cpp | 14 +- .../sys/d3d12/gstd3d12mpeg2dec.h | 3 +- .../sys/d3d12/gstd3d12vp8dec.cpp | 14 +- .../sys/d3d12/gstd3d12vp8dec.h | 3 +- .../sys/d3d12/gstd3d12vp9dec.cpp | 20 +- .../sys/d3d12/gstd3d12vp9dec.h | 3 +- .../gst-plugins-bad/sys/d3d12/plugin.cpp | 38 +- 15 files changed, 524 insertions(+), 239 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.cpp index aa50d3c9e5..a11c1afce3 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.cpp @@ -95,11 +95,9 @@ gst_d3d12_av1_dec_class_init (GstD3D12AV1DecClass * klass, gpointer data) static void gst_d3d12_av1_dec_init (GstD3D12AV1Dec * self) { - GstD3D12AV1DecClass *klass = GST_D3D12_AV1_DEC_GET_CLASS (self); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_AV1_DEC_GET_CLASS (self); - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_AV1, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); } static void @@ -116,8 +114,8 @@ static void gst_d3d12_av1_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstD3D12AV1DecClass *klass = GST_D3D12_AV1_DEC_GET_CLASS (object); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_AV1_DEC_GET_CLASS (object); + auto cdata = &klass->class_data; gst_d3d12_decoder_proxy_get_property (object, prop_id, value, pspec, cdata); } @@ -322,7 +320,7 @@ gst_d3d12_av1_dec_output_picture (GstDxvaAV1Decoder * decoder, void gst_d3d12_av1_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -343,12 +341,14 @@ gst_d3d12_av1_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_av1_dec_debug, "d3d12av1dec", 0, "d3d12av1dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_AV1); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12AV1Dec"); feature_name = g_strdup ("d3d12av1dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.h index 7d977ddb8e..2f6e3e36b9 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12av1dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_av1_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.cpp index 6a9707c8cb..593e73c77e 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.cpp @@ -21,6 +21,8 @@ #include #endif +#include "gstd3d12plugin-config.h" + #include "gstd3d12decoder.h" #include "gstd3d12decodercpbpool.h" #include @@ -38,6 +40,12 @@ #include #include +#ifdef HAVE_GST_D3D11 +#include +#include +#include +#endif + #ifndef GST_DISABLE_GST_DEBUG #define GST_CAT_DEFAULT ensure_debug_category() static GstDebugCategory * @@ -210,6 +218,7 @@ enum GstD3D12DecoderOutputType GST_D3D12_DECODER_OUTPUT_UNKNOWN = 0, GST_D3D12_DECODER_OUTPUT_SYSTEM = (1 << 0), GST_D3D12_DECODER_OUTPUT_D3D12 = (1 << 1), + GST_D3D12_DECODER_OUTPUT_D3D11 = (1 << 2), }; DEFINE_ENUM_FLAG_OPERATORS (GstD3D12DecoderOutputType); @@ -226,6 +235,15 @@ struct DecoderCmdData /* Fence to wait at command record thread */ UINT64 fence_val = 0; + +#ifdef HAVE_GST_D3D11 + ComPtr device11_5; + ComPtr context11_4; + ComPtr fence11; + ComPtr fence12; + + UINT64 fence_val_11 = 0; +#endif }; struct DecoderOutputData @@ -355,6 +373,11 @@ struct _GstD3D12Decoder GstDxvaCodec codec; GstD3D12Device *device; gint64 adapter_luid; + gboolean d3d11_interop; + +#ifdef HAVE_GST_D3D11 + GstD3D11Device *device11; +#endif GstD3D12DecoderPrivate *priv; }; @@ -385,6 +408,9 @@ gst_d3d12_decoder_finalize (GObject * object) auto self = GST_D3D12_DECODER (object); gst_clear_object (&self->device); +#ifdef HAVE_GST_D3D11 + gst_clear_object (&self->device11); +#endif delete self->priv; @@ -392,16 +418,16 @@ gst_d3d12_decoder_finalize (GObject * object) } GstD3D12Decoder * -gst_d3d12_decoder_new (GstDxvaCodec codec, gint64 adapter_luid) +gst_d3d12_decoder_new (const GstD3D12DecoderSubClassData * cdata) { GstD3D12Decoder *self; - g_return_val_if_fail (codec > GST_DXVA_CODEC_NONE, nullptr); - g_return_val_if_fail (codec < GST_DXVA_CODEC_LAST, nullptr); + g_return_val_if_fail (cdata, nullptr); self = (GstD3D12Decoder *) g_object_new (GST_TYPE_D3D12_DECODER, nullptr); - self->codec = codec; - self->adapter_luid = adapter_luid; + self->codec = cdata->codec; + self->adapter_luid = cdata->adapter_luid; + self->d3d11_interop = cdata->d3d11_interop; return self; } @@ -409,13 +435,17 @@ gst_d3d12_decoder_new (GstDxvaCodec codec, gint64 adapter_luid) gboolean gst_d3d12_decoder_open (GstD3D12Decoder * decoder, GstElement * element) { - if (!gst_d3d12_ensure_element_data_for_adapter_luid (element, - decoder->adapter_luid, &decoder->device)) { - GST_ERROR_OBJECT (element, "Cannot create d3d12device"); - return FALSE; + auto priv = decoder->priv; + + { + std::lock_guard < std::recursive_mutex > lk (priv->context_lock); + if (!gst_d3d12_ensure_element_data_for_adapter_luid (element, + decoder->adapter_luid, &decoder->device)) { + GST_ERROR_OBJECT (element, "Cannot create d3d12device"); + return FALSE; + } } - auto priv = decoder->priv; auto cmd = std::make_unique < DecoderCmdData > (); HRESULT hr; @@ -1289,6 +1319,245 @@ gst_d3d12_decoder_can_direct_render (GstD3D12Decoder * self, return TRUE; } +static GstFlowReturn +gst_d3d12_decoder_copy_output_12 (GstD3D12Decoder * self, GstBuffer * srcbuf, + ID3D12Resource * src, D3D12_TEXTURE_COPY_LOCATION dst[2], + D3D12_COMMAND_LIST_TYPE cmd_type, guint64 * fence_val) +{ + auto priv = self->priv; + D3D12_BOX src_box[2]; + std::vector < GstD3D12CopyTextureRegionArgs > copy_args; + + for (guint i = 0; i < 2; i++) { + GstD3D12CopyTextureRegionArgs args; + memset (&args, 0, sizeof (args)); + + args.src = CD3DX12_TEXTURE_COPY_LOCATION (src, i); + args.dst = dst[i]; + + /* FIXME: only 4:2:0 */ + if (i == 0) { + src_box[i].left = GST_ROUND_UP_2 (priv->session->crop_x); + src_box[i].top = GST_ROUND_UP_2 (priv->session->crop_y); + src_box[i].right = GST_ROUND_UP_2 (priv->session->crop_x + + priv->session->output_info.width); + src_box[i].bottom = + GST_ROUND_UP_2 (priv->session->crop_y + + priv->session->output_info.height); + } else { + src_box[i].left = GST_ROUND_UP_2 (priv->session->crop_x) / 2; + src_box[i].top = GST_ROUND_UP_2 (priv->session->crop_y) / 2; + src_box[i].right = + GST_ROUND_UP_2 (priv->session->crop_x + + priv->session->output_info.width) / 2; + src_box[i].bottom = + GST_ROUND_UP_2 (priv->session->crop_y + + priv->session->output_info.height) / 2; + } + + src_box[i].front = 0; + src_box[i].back = 1; + + args.src_box = &src_box[i]; + copy_args.push_back (args); + } + + GstD3D12FenceData *fence_data = nullptr; + if (cmd_type != D3D12_COMMAND_LIST_TYPE_COPY) { + gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, &fence_data); + gst_d3d12_fence_data_push (fence_data, + FENCE_NOTIFY_MINI_OBJECT (gst_buffer_ref (srcbuf))); + } + + guint64 copy_fence_val = 0; + auto copy_ret = gst_d3d12_device_copy_texture_region (self->device, + copy_args.size (), copy_args.data (), fence_data, 0, nullptr, nullptr, + cmd_type, ©_fence_val); + if (!copy_ret) { + GST_ERROR_OBJECT (self, "Couldn't copy decoded texture to output"); + gst_clear_d3d12_fence_data (&fence_data); + return GST_FLOW_ERROR; + } + + if (fence_val) + *fence_val = copy_fence_val; + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_d3d12_decoder_copy_output (GstD3D12Decoder * self, GstBuffer * src_buf, + GstBuffer * dst_buf) +{ + auto priv = self->priv; + auto session = priv->session.get (); + + auto in_dmem = (GstD3D12Memory *) gst_buffer_peek_memory (src_buf, 0); + auto out_mem = gst_buffer_peek_memory (dst_buf, 0); + if (gst_is_d3d12_memory (out_mem)) { + auto out_dmem = GST_D3D12_MEMORY_CAST (out_mem); + if (gst_d3d12_device_is_equal (out_dmem->device, self->device)) { + D3D12_TEXTURE_COPY_LOCATION dst_location[2]; + UINT out_subresource[2]; + guint64 copy_fence_val; + + auto in_resource = gst_d3d12_memory_get_resource_handle (in_dmem); + auto out_resource = gst_d3d12_memory_get_resource_handle (out_dmem); + gst_d3d12_memory_get_subresource_index (out_dmem, 0, &out_subresource[0]); + gst_d3d12_memory_get_subresource_index (out_dmem, 1, &out_subresource[1]); + + dst_location[0] = CD3DX12_TEXTURE_COPY_LOCATION (out_resource, + out_subresource[0]); + dst_location[1] = CD3DX12_TEXTURE_COPY_LOCATION (out_resource, + out_subresource[1]); + + auto ret = gst_d3d12_decoder_copy_output_12 (self, src_buf, in_resource, + dst_location, D3D12_COMMAND_LIST_TYPE_DIRECT, ©_fence_val); + if (ret != GST_FLOW_OK) + return ret; + + auto fence = gst_d3d12_device_get_fence_handle (self->device, + D3D12_COMMAND_LIST_TYPE_DIRECT); + gst_d3d12_memory_set_fence (out_dmem, fence, copy_fence_val, FALSE); + + GST_MINI_OBJECT_FLAG_SET (out_dmem, + GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD); + GST_MINI_OBJECT_FLAG_UNSET (out_dmem, + GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); + + GST_TRACE_OBJECT (self, "d3d12 copy done"); + + return GST_FLOW_OK; + } + } +#ifdef HAVE_GST_D3D11 + else if (session->output_type == GST_D3D12_DECODER_OUTPUT_D3D11 && + self->d3d11_interop && gst_is_d3d11_memory (out_mem)) { + auto out_dmem = GST_D3D11_MEMORY_CAST (out_mem); + if (out_dmem->device == self->device11) { + GstMapInfo out_map; + auto device11 = gst_d3d11_device_get_device_handle (self->device11); + auto in_texture11 = + gst_d3d12_memory_get_d3d11_texture (in_dmem, device11); + + if (!in_texture11) { + GST_ERROR_OBJECT (self, + "Couldn't get d3d11 texture from decoded texture"); + return GST_FLOW_ERROR; + } + + if (!gst_memory_map (out_mem, &out_map, + (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) { + GST_ERROR_OBJECT (self, "Couldn't map output d3d11 memory"); + return GST_FLOW_ERROR; + } + + HRESULT hr; + { + GstD3D11DeviceLockGuard device11_lk (self->device11); + D3D11_BOX src_box = { }; + src_box.left = GST_ROUND_UP_2 (session->crop_x); + src_box.top = GST_ROUND_UP_2 (session->crop_y); + src_box.right = GST_ROUND_UP_2 (session->crop_x + + session->output_info.width); + src_box.bottom = GST_ROUND_UP_2 (session->crop_y + + session->output_info.height); + src_box.front = 0; + src_box.back = 1; + + auto out_texture11 = gst_d3d11_memory_get_resource_handle (out_dmem); + auto out_subresource = + gst_d3d11_memory_get_subresource_index (out_dmem); + + priv->cmd->context11_4->CopySubresourceRegion (out_texture11, + out_subresource, 0, 0, 0, in_texture11, 0, &src_box); + priv->cmd->fence_val_11++; + hr = priv->cmd->context11_4->Signal (priv->cmd->fence11.Get (), + priv->cmd->fence_val_11); + } + + gst_memory_unmap (out_mem, &out_map); + + if (!gst_d3d11_result (hr, self->device11)) { + GST_ERROR_OBJECT (self, "Signal failed"); + return GST_FLOW_ERROR; + } + + /* Set d3d11 device signalled fence to d3d12 memory. + * d3d12 buffer pool or allocator will wait for this fence + * to keep resource alive if it's still being used by d3d11 */ + gst_d3d12_memory_set_fence (in_dmem, priv->cmd->fence12.Get (), + priv->cmd->fence_val_11, FALSE); + + GST_TRACE_OBJECT (self, "Copy done via d3d11 interop"); + + return GST_FLOW_OK; + } + } +#endif + + if (!gst_d3d12_decoder_ensure_staging_texture (self)) { + GST_ERROR_OBJECT (self, "Couldn't allocate staging texture"); + return GST_FLOW_ERROR; + } + + auto in_resource = gst_d3d12_memory_get_resource_handle (in_dmem); + D3D12_TEXTURE_COPY_LOCATION dst_location[2]; + + dst_location[0] = CD3DX12_TEXTURE_COPY_LOCATION (session->staging.Get (), + session->layout[0]); + dst_location[1] = CD3DX12_TEXTURE_COPY_LOCATION (session->staging.Get (), + session->layout[1]); + + guint64 copy_fence_val; + auto ret = gst_d3d12_decoder_copy_output_12 (self, src_buf, in_resource, + dst_location, D3D12_COMMAND_LIST_TYPE_COPY, ©_fence_val); + if (ret != GST_FLOW_OK) { + GST_ERROR_OBJECT (self, "Couldn't download to staging buffer"); + return ret; + } + + auto hr = gst_d3d12_device_fence_wait (self->device, + D3D12_COMMAND_LIST_TYPE_COPY, copy_fence_val); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't wait for fence"); + return GST_FLOW_ERROR; + } + + guint8 *map_data; + GstVideoFrame vframe; + hr = session->staging->Map (0, nullptr, (void **) &map_data); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't map staging texture"); + return GST_FLOW_ERROR; + } + + if (!gst_video_frame_map (&vframe, + &session->output_info, dst_buf, GST_MAP_WRITE)) { + GST_ERROR_OBJECT (self, "Couldn't map output buffer"); + session->staging->Unmap (0, nullptr); + return GST_FLOW_ERROR; + } + + for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&vframe); i++) { + guint8 *src_data = map_data + session->layout[i].Offset; + guint8 *dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, i); + gint width = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, i) * + GST_VIDEO_FRAME_COMP_PSTRIDE (&vframe, i); + + for (gint j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); j++) { + memcpy (dst_data, src_data, width); + dst_data += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, i); + src_data += session->layout[i].Footprint.RowPitch; + } + } + + session->staging->Unmap (0, nullptr); + gst_video_frame_unmap (&vframe); + + return GST_FLOW_OK; +} + static GstFlowReturn gst_d3d12_decoder_process_output (GstD3D12Decoder * self, GstVideoDecoder * videodec, GstVideoCodecFrame * frame, @@ -1297,10 +1566,6 @@ gst_d3d12_decoder_process_output (GstD3D12Decoder * self, { GstFlowReturn ret = GST_FLOW_ERROR; GstBuffer *buffer; - GstD3D12Memory *dmem; - ID3D12Resource *resource; - UINT subresource[2]; - HRESULT hr; bool attach_crop_meta = false; auto priv = self->priv; @@ -1337,153 +1602,30 @@ gst_d3d12_decoder_process_output (GstD3D12Decoder * self, buffer = decoder_pic->output_buffer ? decoder_pic->output_buffer : decoder_pic->buffer; - dmem = (GstD3D12Memory *) gst_buffer_peek_memory (buffer, 0); priv->session->lock.lock (); if (gst_d3d12_decoder_can_direct_render (self, videodec, decoder_pic->buffer, display_width, display_height)) { GST_LOG_OBJECT (self, "Outputting without copy"); - GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD); - GST_MINI_OBJECT_FLAG_UNSET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); + auto mem = gst_buffer_peek_memory (buffer, 0); + GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD); + GST_MINI_OBJECT_FLAG_UNSET (mem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); if (priv->session->need_crop) attach_crop_meta = true; frame->output_buffer = gst_buffer_ref (buffer); } else { - ID3D12Resource *out_resource = nullptr; - UINT out_subresource[2]; - ret = gst_video_decoder_allocate_output_frame (videodec, frame); if (ret != GST_FLOW_OK) { GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer"); goto error; } - auto out_mem = gst_buffer_peek_memory (frame->output_buffer, 0); - if (gst_is_d3d12_memory (out_mem)) { - auto out_dmem = GST_D3D12_MEMORY_CAST (out_mem); - if (gst_d3d12_device_is_equal (dmem->device, self->device)) { - out_resource = gst_d3d12_memory_get_resource_handle (out_dmem); - gst_d3d12_memory_get_subresource_index (out_dmem, 0, - &out_subresource[0]); - gst_d3d12_memory_get_subresource_index (out_dmem, 1, - &out_subresource[1]); - - GST_MINI_OBJECT_FLAG_SET (out_dmem, - GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD); - GST_MINI_OBJECT_FLAG_UNSET (out_dmem, - GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); - } - } - - if (!out_resource && !gst_d3d12_decoder_ensure_staging_texture (self)) { - GST_ERROR_OBJECT (videodec, "Couldn't allocate staging texture"); - ret = GST_FLOW_ERROR; + ret = gst_d3d12_decoder_copy_output (self, buffer, frame->output_buffer); + if (ret != GST_FLOW_OK) goto error; - } - - resource = gst_d3d12_memory_get_resource_handle (dmem); - - gst_d3d12_memory_get_subresource_index (dmem, 0, &subresource[0]); - gst_d3d12_memory_get_subresource_index (dmem, 1, &subresource[1]); - - /* Copy texture to staging */ - D3D12_BOX src_box[2]; - std::vector < GstD3D12CopyTextureRegionArgs > copy_args; - - for (guint i = 0; i < 2; i++) { - GstD3D12CopyTextureRegionArgs args; - memset (&args, 0, sizeof (args)); - - args.src = CD3DX12_TEXTURE_COPY_LOCATION (resource, subresource[i]); - - if (out_resource) { - args.dst = - CD3DX12_TEXTURE_COPY_LOCATION (out_resource, out_subresource[i]); - } else { - args.dst = - CD3DX12_TEXTURE_COPY_LOCATION (priv->session->staging.Get (), - priv->session->layout[i]); - } - - /* FIXME: only 4:2:0 */ - if (i == 0) { - src_box[i].left = GST_ROUND_UP_2 (priv->session->crop_x); - src_box[i].top = GST_ROUND_UP_2 (priv->session->crop_y); - src_box[i].right = GST_ROUND_UP_2 (priv->session->crop_x + - priv->session->output_info.width); - src_box[i].bottom = - GST_ROUND_UP_2 (priv->session->crop_y + - priv->session->output_info.height); - } else { - src_box[i].left = GST_ROUND_UP_2 (priv->session->crop_x) / 2; - src_box[i].top = GST_ROUND_UP_2 (priv->session->crop_y) / 2; - src_box[i].right = - GST_ROUND_UP_2 (priv->session->crop_x + - priv->session->output_info.width) / 2; - src_box[i].bottom = - GST_ROUND_UP_2 (priv->session->crop_y + - priv->session->output_info.height) / 2; - } - - src_box[i].front = 0; - src_box[i].back = 1; - - args.src_box = &src_box[i]; - copy_args.push_back (args); - } - - guint64 copy_fence_val = 0; - GstD3D12FenceData *fence_data = nullptr; - D3D12_COMMAND_LIST_TYPE queue_type = D3D12_COMMAND_LIST_TYPE_COPY; - if (out_resource) { - queue_type = D3D12_COMMAND_LIST_TYPE_DIRECT; - gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, &fence_data); - gst_d3d12_fence_data_push (fence_data, - FENCE_NOTIFY_MINI_OBJECT (gst_buffer_ref (buffer))); - } - - gst_d3d12_device_copy_texture_region (self->device, copy_args.size (), - copy_args.data (), fence_data, 0, nullptr, nullptr, queue_type, - ©_fence_val); - auto fence = gst_d3d12_device_get_fence_handle (self->device, queue_type); - - if (!out_resource) { - guint8 *map_data; - GstVideoFrame vframe; - - gst_d3d12_device_fence_wait (self->device, queue_type, copy_fence_val); - - hr = priv->session->staging->Map (0, nullptr, (void **) &map_data); - if (!gst_d3d12_result (hr, self->device)) { - ret = GST_FLOW_ERROR; - goto error; - } - - gst_video_frame_map (&vframe, - &priv->session->output_info, frame->output_buffer, GST_MAP_WRITE); - - for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&vframe); i++) { - guint8 *src = map_data + priv->session->layout[i].Offset; - guint8 *dst = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, i); - gint width = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, i) * - GST_VIDEO_FRAME_COMP_PSTRIDE (&vframe, i); - - for (gint j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); j++) { - memcpy (dst, src, width); - dst += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, i); - src += priv->session->layout[i].Footprint.RowPitch; - } - } - - priv->session->staging->Unmap (0, nullptr); - gst_video_frame_unmap (&vframe); - } else { - gst_d3d12_buffer_set_fence (frame->output_buffer, - fence, copy_fence_val, FALSE); - } } priv->session->lock.unlock (); @@ -1646,6 +1788,12 @@ gst_d3d12_decoder_negotiate (GstD3D12Decoder * decoder, GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY)) { allowed_types |= GST_D3D12_DECODER_OUTPUT_D3D12; } +#ifdef HAVE_GST_D3D11 + if (gst_caps_features_contains (features, + GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) { + allowed_types |= GST_D3D12_DECODER_OUTPUT_D3D11; + } +#endif } } gst_clear_caps (&peer_caps); @@ -1685,6 +1833,57 @@ gst_d3d12_decoder_negotiate (GstD3D12Decoder * decoder, g_clear_pointer (&priv->session->output_state, gst_video_codec_state_unref); priv->session->output_state = state; +#ifdef HAVE_GST_D3D11 + /* Try d3d11 only if downstream does not support d3d12 but does d3d11, + * otherwise decoder will create unnecessary d3d11 device */ + if ((allowed_types & GST_D3D12_DECODER_OUTPUT_D3D11) == + GST_D3D12_DECODER_OUTPUT_D3D11 && + (allowed_types & GST_D3D12_DECODER_OUTPUT_D3D12) != + GST_D3D12_DECODER_OUTPUT_D3D12) { + auto elem = GST_ELEMENT (videodec); + if (decoder->d3d11_interop) { + if (gst_d3d11_ensure_element_data_for_adapter_luid (elem, + decoder->adapter_luid, &decoder->device11)) { + if (!priv->cmd->device11_5) { + auto device11 = + gst_d3d11_device_get_device_handle (decoder->device11); + device11->QueryInterface (IID_PPV_ARGS (&priv->cmd->device11_5)); + } + + if (priv->cmd->device11_5 && !priv->cmd->context11_4) { + ComPtr < ID3D11DeviceContext > context11; + ComPtr < ID3D11DeviceContext4 > context11_4; + priv->cmd->device11_5->GetImmediateContext (&context11); + context11.As (&priv->cmd->context11_4); + } + + if (priv->cmd->context11_4 && !priv->cmd->fence11) { + priv->cmd->device11_5->CreateFence (0, D3D11_FENCE_FLAG_SHARED, + IID_PPV_ARGS (&priv->cmd->fence11)); + } + + if (priv->cmd->fence11 && !priv->cmd->fence12) { + HANDLE handle; + auto hr = priv->cmd->fence11->CreateSharedHandle (nullptr, + GENERIC_ALL, nullptr, &handle); + if (SUCCEEDED (hr)) { + priv->cmd->device->OpenSharedHandle (handle, + IID_PPV_ARGS (&priv->cmd->fence12)); + CloseHandle (handle); + } + } + + if (!priv->cmd->fence12) + allowed_types &= ~GST_D3D12_DECODER_OUTPUT_D3D11; + } else { + allowed_types &= ~GST_D3D12_DECODER_OUTPUT_D3D11; + } + } else if (!gst_d3d11_ensure_element_data (elem, -1, &decoder->device11)) { + allowed_types &= ~GST_D3D12_DECODER_OUTPUT_D3D11; + } + } +#endif + auto prev_output_type = priv->session->output_type; if (prev_output_type != GST_D3D12_DECODER_OUTPUT_UNKNOWN && (prev_output_type & allowed_types) == prev_output_type) { @@ -1692,14 +1891,25 @@ gst_d3d12_decoder_negotiate (GstD3D12Decoder * decoder, } else { if ((allowed_types & GST_D3D12_DECODER_OUTPUT_D3D12) != 0) priv->session->output_type = GST_D3D12_DECODER_OUTPUT_D3D12; + else if ((allowed_types & GST_D3D12_DECODER_OUTPUT_D3D11) != 0) + priv->session->output_type = GST_D3D12_DECODER_OUTPUT_D3D11; else priv->session->output_type = GST_D3D12_DECODER_OUTPUT_SYSTEM; } - if (priv->session->output_type == GST_D3D12_DECODER_OUTPUT_D3D12) { - gst_caps_set_features (state->caps, 0, - gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY)); - priv->session->output_type = GST_D3D12_DECODER_OUTPUT_D3D12; + switch (priv->session->output_type) { + case GST_D3D12_DECODER_OUTPUT_D3D12: + gst_caps_set_features (state->caps, 0, + gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY)); + break; +#ifdef HAVE_GST_D3D11 + case GST_D3D12_DECODER_OUTPUT_D3D11: + gst_caps_set_features (state->caps, 0, + gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)); + break; +#endif + default: + break; } GST_DEBUG_OBJECT (decoder, "Selected output type %d", @@ -1756,13 +1966,28 @@ gst_d3d12_decoder_decide_allocation (GstD3D12Decoder * decoder, "Downstream pool is not d3d12, will create new one"); gst_clear_object (&pool); } else { - GstD3D12BufferPool *dpool = GST_D3D12_BUFFER_POOL (pool); + auto dpool = GST_D3D12_BUFFER_POOL (pool); if (!gst_d3d12_device_is_equal (dpool->device, decoder->device)) { GST_DEBUG_OBJECT (videodec, "Different device, will create new one"); gst_clear_object (&pool); } } } +#ifdef HAVE_GST_D3D11 + if (priv->session->output_type == GST_D3D12_DECODER_OUTPUT_D3D11) { + if (!GST_IS_D3D12_BUFFER_POOL (pool)) { + GST_DEBUG_OBJECT (videodec, + "Downstream pool is not d3d11, will create new one"); + gst_clear_object (&pool); + } else if (decoder->d3d11_interop) { + auto dpool = GST_D3D11_BUFFER_POOL (pool); + if (dpool->device != decoder->device11) { + GST_DEBUG_OBJECT (videodec, "Different device, will create new one"); + gst_clear_object (&pool); + } + } + } +#endif } if (!pool) { @@ -1770,6 +1995,11 @@ gst_d3d12_decoder_decide_allocation (GstD3D12Decoder * decoder, case GST_D3D12_DECODER_OUTPUT_D3D12: pool = gst_d3d12_buffer_pool_new (decoder->device); break; +#ifdef HAVE_GST_D3D11 + case GST_D3D12_DECODER_OUTPUT_D3D11: + pool = gst_d3d11_buffer_pool_new (decoder->device11); + break; +#endif default: pool = gst_video_buffer_pool_new (); break; @@ -1783,13 +2013,12 @@ gst_d3d12_decoder_decide_allocation (GstD3D12Decoder * decoder, gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); if (priv->session->output_type == GST_D3D12_DECODER_OUTPUT_D3D12) { - GstD3D12AllocationParams *params; GstVideoAlignment align; gint width, height; gst_video_alignment_reset (&align); - params = gst_buffer_pool_config_get_d3d12_allocation_params (config); + auto params = gst_buffer_pool_config_get_d3d12_allocation_params (config); if (!params) { params = gst_d3d12_allocation_params_new (decoder->device, &vinfo, GST_D3D12_ALLOCATION_FLAG_DEFAULT, @@ -1811,14 +2040,20 @@ gst_d3d12_decoder_decide_allocation (GstD3D12Decoder * decoder, gst_d3d12_allocation_params_alignment (params, &align); gst_buffer_pool_config_set_d3d12_allocation_params (config, params); gst_d3d12_allocation_params_free (params); - - - GST_DEBUG_OBJECT (videodec, "Downstream min buffres: %d", min); - - /* We will not use downstream pool for decoding, and therefore preallocation - * is unnecessary. So, Non-zero min buffer will be a waste of GPU memory */ - min = 0; } +#ifdef HAVE_GST_D3D11 + else if (priv->session->output_type == GST_D3D12_DECODER_OUTPUT_D3D11) { + auto params = gst_buffer_pool_config_get_d3d11_allocation_params (config); + if (!params) { + params = gst_d3d11_allocation_params_new (decoder->device11, &vinfo, + GST_D3D11_ALLOCATION_FLAG_DEFAULT, + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0); + } + + gst_buffer_pool_config_set_d3d11_allocation_params (config, params); + gst_d3d11_allocation_params_free (params); + } +#endif gst_buffer_pool_set_config (pool, config); /* d3d12 buffer pool will update buffer size based on allocated texture, @@ -1850,6 +2085,15 @@ gst_d3d12_decoder_set_context (GstD3D12Decoder * decoder, GstElement * element, std::lock_guard < std::recursive_mutex > lk (priv->context_lock); gst_d3d12_handle_set_context_for_adapter_luid (element, context, decoder->adapter_luid, &decoder->device); +#ifdef HAVE_GST_D3D11 + if (decoder->d3d11_interop) { + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, decoder->adapter_luid, &decoder->device11); + } else { + /* Since we will do system copy, accept any device */ + gst_d3d11_handle_set_context (element, context, -1, &decoder->device11); + } +#endif } gboolean @@ -1861,6 +2105,11 @@ gst_d3d12_decoder_handle_query (GstD3D12Decoder * decoder, GstElement * element, auto priv = decoder->priv; std::lock_guard < std::recursive_mutex > lk (priv->context_lock); +#ifdef HAVE_GST_D3D11 + if (gst_d3d11_handle_context_query (element, query, decoder->device11)) + return TRUE; +#endif + return gst_d3d12_handle_context_query (element, query, decoder->device); } @@ -1871,14 +2120,6 @@ enum PROP_DECODER_VENDOR_ID, }; -struct _GstD3D12DecoderClassData -{ - GstD3D12DecoderSubClassData subclass_data; - GstCaps *sink_caps; - GstCaps *src_caps; - gchar *description; -}; - static void gst_d3d12_decoder_get_profiles (const GUID & profile, std::vector < std::string > &list) @@ -2102,11 +2343,17 @@ gst_d3d12_decoder_check_feature_support (GstD3D12Device * device, } /* *INDENT-ON* */ - GstCaps *sink_caps = gst_caps_from_string (sink_caps_string.c_str ()); - GstCaps *raw_caps = gst_caps_from_string (src_caps_string.c_str ()); - GstCaps *src_caps = gst_caps_copy (raw_caps); + auto sink_caps = gst_caps_from_string (sink_caps_string.c_str ()); + auto raw_caps = gst_caps_from_string (src_caps_string.c_str ()); + auto src_caps = gst_caps_copy (raw_caps); gst_caps_set_features_simple (src_caps, gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY)); +#ifdef HAVE_GST_D3D11 + auto d3d11_caps = gst_caps_copy (raw_caps); + gst_caps_set_features_simple (d3d11_caps, + gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)); + gst_caps_append (src_caps, d3d11_caps); +#endif gst_caps_append (src_caps, raw_caps); gint max_res = MAX (max_resolution.width, max_resolution.height); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.h index f9788a5301..b854a60f0e 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12decoder.h @@ -31,14 +31,21 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (GstD3D12Decoder, gst_d3d12_decoder, GST, D3D12_DECODER, GstObject); -typedef struct _GstD3D12DecoderClassData GstD3D12DecoderClassData; - struct GstD3D12DecoderSubClassData { GstDxvaCodec codec; gint64 adapter_luid; guint device_id; guint vendor_id; + gboolean d3d11_interop; +}; + +struct GstD3D12DecoderClassData +{ + GstD3D12DecoderSubClassData subclass_data; + GstCaps *sink_caps; + GstCaps *src_caps; + gchar *description; }; #define GST_D3D12_DECODER_DEFINE_TYPE(ModuleObjName,module_obj_name,MODULE,OBJ_NAME,ParentName) \ @@ -100,8 +107,7 @@ struct GstD3D12DecoderSubClassData static GstFlowReturn module_obj_name##_duplicate_picture (ParentName * decoder, \ GstCodecPicture * src, GstCodecPicture * dst); -GstD3D12Decoder * gst_d3d12_decoder_new (GstDxvaCodec codec, - gint64 adapter_luid); +GstD3D12Decoder * gst_d3d12_decoder_new (const GstD3D12DecoderSubClassData * cdata); gboolean gst_d3d12_decoder_open (GstD3D12Decoder * decoder, GstElement * element); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.cpp index 3f5a15d625..46a01ea876 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.cpp @@ -95,17 +95,15 @@ gst_d3d12_h264_dec_class_init (GstD3D12H264DecClass * klass, gpointer data) static void gst_d3d12_h264_dec_init (GstD3D12H264Dec * self) { - GstD3D12H264DecClass *klass = GST_D3D12_H264_DEC_GET_CLASS (self); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_H264_DEC_GET_CLASS (self); - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_H264, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); } static void gst_d3d12_h264_dec_finalize (GObject * object) { - GstD3D12H264Dec *self = GST_D3D12_H264_DEC (object); + auto self = GST_D3D12_H264_DEC (object); gst_object_unref (self->decoder); @@ -116,8 +114,8 @@ static void gst_d3d12_h264_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstD3D12H264DecClass *klass = GST_D3D12_H264_DEC_GET_CLASS (object); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_H264_DEC_GET_CLASS (object); + auto cdata = &klass->class_data; gst_d3d12_decoder_proxy_get_property (object, prop_id, value, pspec, cdata); } @@ -125,7 +123,7 @@ gst_d3d12_h264_dec_get_property (GObject * object, guint prop_id, static void gst_d3d12_h264_dec_set_context (GstElement * element, GstContext * context) { - GstD3D12H264Dec *self = GST_D3D12_H264_DEC (element); + auto self = GST_D3D12_H264_DEC (element); gst_d3d12_decoder_set_context (self->decoder, element, context); @@ -322,7 +320,7 @@ gst_d3d12_h264_dec_output_picture (GstDxvaH264Decoder * decoder, void gst_d3d12_h264_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -343,12 +341,14 @@ gst_d3d12_h264_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_h264_dec_debug, "d3d12h264dec", 0, "d3d12h264dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_H264); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12H264Dec"); feature_name = g_strdup ("d3d12h264dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.h index afd8994c13..baf731dbe5 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h264dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_h264_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.cpp index 2074971fd9..8654c481c0 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.cpp @@ -93,11 +93,9 @@ gst_d3d12_h265_dec_class_init (GstD3D12H265DecClass * klass, gpointer data) static void gst_d3d12_h265_dec_init (GstD3D12H265Dec * self) { - GstD3D12H265DecClass *klass = GST_D3D12_H265_DEC_GET_CLASS (self); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_H265_DEC_GET_CLASS (self); - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_H265, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); } static void @@ -114,8 +112,8 @@ static void gst_d3d12_h265_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstD3D12H265DecClass *klass = GST_D3D12_H265_DEC_GET_CLASS (object); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_H265_DEC_GET_CLASS (object); + auto cdata = &klass->class_data; gst_d3d12_decoder_proxy_get_property (object, prop_id, value, pspec, cdata); } @@ -311,7 +309,7 @@ gst_d3d12_h265_dec_output_picture (GstDxvaH265Decoder * decoder, void gst_d3d12_h265_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -332,12 +330,14 @@ gst_d3d12_h265_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_h265_dec_debug, "d3d12h265dec", 0, "d3d12h265dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_H265); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12H265Dec"); feature_name = g_strdup ("d3d12h265dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.h index 3de9de9260..d3c281850b 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12h265dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_h265_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.cpp index 992b1e3372..3eba22054c 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.cpp @@ -98,10 +98,8 @@ static void gst_d3d12_mpeg2_dec_init (GstD3D12Mpeg2Dec * self) { auto klass = GST_D3D12_MPEG2_DEC_GET_CLASS (self); - auto cdata = &klass->class_data; - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_MPEG2, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); gst_dxva_mpeg2_decoder_disable_postproc (GST_DXVA_MPEG2_DECODER (self)); } @@ -325,7 +323,7 @@ gst_d3d12_mpeg2_dec_output_picture (GstDxvaMpeg2Decoder * decoder, void gst_d3d12_mpeg2_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -346,12 +344,14 @@ gst_d3d12_mpeg2_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_mpeg2_dec_debug, "d3d12mpeg2dec", 0, "d3d12mpeg2dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_MPEG2); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12Mpeg2Dec"); feature_name = g_strdup ("d3d12mpeg2dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.h index 3eff1d3154..39380d99a7 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12mpeg2dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_mpeg2_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.cpp index a5be313a06..8be48ab6f6 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.cpp @@ -94,10 +94,8 @@ static void gst_d3d12_vp8_dec_init (GstD3D12Vp8Dec * self) { auto klass = GST_D3D12_VP8_DEC_GET_CLASS (self); - auto cdata = &klass->class_data; - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_VP8, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); } static void @@ -311,7 +309,7 @@ gst_d3d12_vp8_dec_output_picture (GstDxvaVp8Decoder * decoder, void gst_d3d12_vp8_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -332,12 +330,14 @@ gst_d3d12_vp8_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_vp8_dec_debug, "d3d12vp8dec", 0, "d3d12vp8dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_VP8); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12Vp8Dec"); feature_name = g_strdup ("d3d12vp8dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.h index 3759de3195..3a1149dd43 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp8dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_vp8_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.cpp index 86e57258ca..55e3db8d39 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.cpp @@ -95,11 +95,9 @@ gst_d3d12_vp9_dec_class_init (GstD3D12Vp9DecClass * klass, gpointer data) static void gst_d3d12_vp9_dec_init (GstD3D12Vp9Dec * self) { - GstD3D12Vp9DecClass *klass = GST_D3D12_VP9_DEC_GET_CLASS (self); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_VP9_DEC_GET_CLASS (self); - self->decoder = gst_d3d12_decoder_new (GST_DXVA_CODEC_VP9, - cdata->adapter_luid); + self->decoder = gst_d3d12_decoder_new (&klass->class_data); } static void @@ -116,8 +114,8 @@ static void gst_d3d12_vp9_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstD3D12Vp9DecClass *klass = GST_D3D12_VP9_DEC_GET_CLASS (object); - GstD3D12DecoderSubClassData *cdata = &klass->class_data; + auto klass = GST_D3D12_VP9_DEC_GET_CLASS (object); + auto cdata = &klass->class_data; gst_d3d12_decoder_proxy_get_property (object, prop_id, value, pspec, cdata); } @@ -324,7 +322,7 @@ gst_d3d12_vp9_dec_output_picture (GstDxvaVp9Decoder * decoder, void gst_d3d12_vp9_dec_register (GstPlugin * plugin, GstD3D12Device * device, - ID3D12VideoDevice * video_device, guint rank) + ID3D12VideoDevice * video_device, guint rank, gboolean d3d11_interop) { GType type; gchar *type_name; @@ -345,12 +343,14 @@ gst_d3d12_vp9_dec_register (GstPlugin * plugin, GstD3D12Device * device, GST_DEBUG_CATEGORY_INIT (gst_d3d12_vp9_dec_debug, "d3d12vp9dec", 0, "d3d12vp9dec"); - type_info.class_data = - gst_d3d12_decoder_check_feature_support (device, video_device, + auto cdata = gst_d3d12_decoder_check_feature_support (device, video_device, GST_DXVA_CODEC_VP9); - if (!type_info.class_data) + if (!cdata) return; + cdata->subclass_data.d3d11_interop = d3d11_interop; + type_info.class_data = cdata; + type_name = g_strdup ("GstD3D12Vp9Dec"); feature_name = g_strdup ("d3d12vp9dec"); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.h index 63089ddda0..fbc5bde4b1 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12vp9dec.h @@ -26,7 +26,8 @@ G_BEGIN_DECLS void gst_d3d12_vp9_dec_register (GstPlugin * plugin, GstD3D12Device * device, ID3D12VideoDevice * video_device, - guint rank); + guint rank, + gboolean d3d11_interop); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/plugin.cpp b/subprojects/gst-plugins-bad/sys/d3d12/plugin.cpp index 52e931fee8..8e69b5dd9f 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/plugin.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/plugin.cpp @@ -55,6 +55,9 @@ #ifdef HAVE_GST_D3D11 #include "gstd3d12memorycopy.h" +#include +#include +#include #else #include "gstd3d12download.h" #include "gstd3d12upload.h" @@ -94,6 +97,7 @@ plugin_init (GstPlugin * plugin) ID3D12Device *device_handle; ComPtr < ID3D12VideoDevice > video_device; HRESULT hr; + gboolean d3d11_interop = FALSE; device = gst_d3d12_device_new (i); if (!device) @@ -106,21 +110,43 @@ plugin_init (GstPlugin * plugin) gst_object_unref (device); continue; } +#ifdef HAVE_GST_D3D11 + gint64 luid; + g_object_get (device, "adapter-luid", &luid, nullptr); + auto device11 = gst_d3d11_device_new_for_adapter_luid (luid, + D3D11_CREATE_DEVICE_BGRA_SUPPORT); + if (device11 && gst_d3d11_device_d3d12_import_supported (device11)) { + auto device11_handle = gst_d3d11_device_get_device_handle (device11); + ComPtr < ID3D11Device5 > device11_5; + hr = device11_handle->QueryInterface (IID_PPV_ARGS (&device11_5)); + if (SUCCEEDED (hr)) { + ComPtr < ID3D11DeviceContext > context11; + ComPtr < ID3D11DeviceContext4 > context11_4; + device11_5->GetImmediateContext (&context11); + hr = context11.As (&context11_4); + if (SUCCEEDED (hr)) + d3d11_interop = TRUE; + } + } + + gst_clear_object (&device11); +#endif + have_video_device = true; gst_d3d12_mpeg2_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_h264_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_h265_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_vp8_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_vp9_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_av1_dec_register (plugin, device, video_device.Get (), - decoder_rank); + decoder_rank, d3d11_interop); gst_d3d12_h264_enc_register (plugin, device, video_device.Get (), GST_RANK_NONE);