Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Tong Wu <wutong1208@outlook.com>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Cc: Araz Iusubov <Primeadvice@gmail.com>
Subject: Re: [FFmpeg-devel] [PATCH] avcodec/amfenc: DX12 Reference-only feature support
Date: Mon, 10 Feb 2025 15:18:18 +0000
Message-ID: <SY7P300MB0845AA075A9FB23405714100C7F22@SY7P300MB0845.AUSP300.PROD.OUTLOOK.COM> (raw)
In-Reply-To: <20250130140934.1800-1-Primeadvice@gmail.com>

Araz Iusubov:
>Subject: [FFmpeg-devel] [PATCH] avcodec/amfenc: DX12 Reference-only feature
>support
>
>The Reference-Only feature in DirectX 12 is a memory optimization technique
>designed for video decoding scenarios.
>This feature requires that reference resources must be allocated with the
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY resource flag.
>Reference textures must also be separated from output textures.
>This feature is not supported in the current version of ffmpeg.
>Since AMD GPU uses this feature in Direct 12 decoder, ffmpeg does not support
>AMD GPU Direct 12 decoding.
>To properly support the Reference-Only feature, two parallel resource pools must
>be configured and managed:
>General Resource Pool:
>Contains resources used for output decoded frames.
>Defined in AVHWFramesContext and manages the final decoded textures.
>Reference-Only Resource Pool:
>Intended for storing reference frame resources.
>Resources created with the
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY flag are allocated
>to AVBufferPool.
>
>---
> libavcodec/d3d12va_decode.c   | 58 ++++++++++++++++++++++++++++---
> libavutil/hwcontext_d3d12va.c | 65 ++++++++++++++++++++++++++++++++---
> 2 files changed, 115 insertions(+), 8 deletions(-)
>
>diff --git a/libavcodec/d3d12va_decode.c b/libavcodec/d3d12va_decode.c index
>3b8978635e..8916f94d10 100644
>--- a/libavcodec/d3d12va_decode.c
>+++ b/libavcodec/d3d12va_decode.c
>@@ -51,11 +51,19 @@ unsigned ff_d3d12va_get_surface_index(const
>AVCodecContext *avctx,
>                                       D3D12VADecodeContext *ctx, const AVFrame *frame,
>                                       int curr)  {
>+    AVHWFramesContext      *frames_ctx   = D3D12VA_FRAMES_CONTEXT(avctx);
>+    AVD3D12VAFramesContext *frames_hwctx = frames_ctx->hwctx;
>+
>     AVD3D12VAFrame *f;
>     ID3D12Resource *res;
>     unsigned i;
>
>-    f = (AVD3D12VAFrame *)frame->data[0];
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        f = (AVD3D12VAFrame*)frame->data[1];
>+    } else {
>+        f = (AVD3D12VAFrame*)frame->data[0];
>+    }
>+
>     if (!f)
>         goto fail;
>
>@@ -250,6 +258,11 @@ static int d3d12va_create_decoder(AVCodecContext
>*avctx)
>         return AVERROR_PATCHWELCOME;
>     }

Need to handle when DecodeTier == D3D12_VIDEO_DECODE_TIER_2?

>
>+    if (feature.ConfigurationFlags &
>D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATI
>ONS_REQUIRED) {
>+        frames_hwctx->flags |=
>(D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY |
>D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
>+        av_log(avctx, AV_LOG_INFO, "Reference-Only Allocations are required for
>this configuration.\n");
>+    }
>+
>     desc = (D3D12_VIDEO_DECODER_DESC) {
>         .NodeMask = 0,
>         .Configuration = ctx->cfg,
>@@ -440,8 +453,19 @@ int ff_d3d12va_common_end_frame(AVCodecContext
>*avctx, AVFrame *frame,
>     D3D12VADecodeContext   *ctx               = D3D12VA_DECODE_CONTEXT(avctx);
>     ID3D12Resource         *buffer            = NULL;
>     ID3D12CommandAllocator *command_allocator = NULL;
>-    AVD3D12VAFrame         *f                 = (AVD3D12VAFrame *)frame->data[0];
>-    ID3D12Resource         *resource          = (ID3D12Resource *)f->texture;
>+    AVHWFramesContext      *frames_ctx        =
>D3D12VA_FRAMES_CONTEXT(avctx);
>+    AVD3D12VAFramesContext *frames_hwctx      = frames_ctx->hwctx;
>+    AVD3D12VAFrame         *f                 = NULL;
>+    AVD3D12VAFrame         *output_data       = NULL;
>+
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        f           = (AVD3D12VAFrame*)frame->data[1];
>+        output_data = (AVD3D12VAFrame*)frame->data[0];
>+    } else {
>+        f           = (AVD3D12VAFrame*)frame->data[0];
>+    }
>+
>+    ID3D12Resource* resource = (ID3D12Resource*)f->texture;
>
>     ID3D12VideoDecodeCommandList *cmd_list = ctx->command_list;
>     D3D12_RESOURCE_BARRIER barriers[32] = { 0 }; @@ -469,6 +493,14 @@ int
>ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
>         .pOutputTexture2D    = resource,
>     };
>
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        output_args.pOutputTexture2D = output_data->texture;
>+
>+        output_args.ConversionArguments.Enable               = 1;
>+        output_args.ConversionArguments.pReferenceTexture2D  = resource;
>+        output_args.ConversionArguments.ReferenceSubresource = 0;
>+    }
>+
>     UINT num_barrier = 1;
>     barriers[0] = (D3D12_RESOURCE_BARRIER) {
>         .Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
>@@ -481,6 +513,20 @@ int ff_d3d12va_common_end_frame(AVCodecContext
>*avctx, AVFrame *frame,
>         },
>     };
>
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        barriers[1] = (D3D12_RESOURCE_BARRIER) {
>+            .Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
>+            .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
>+            .Transition = {
>+                .pResource   = output_data->texture,
>+                .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
>+                .StateBefore = D3D12_RESOURCE_STATE_COMMON,
>+                .StateAfter  = D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
>+            },
>+        };
>+        num_barrier++;
>+    }
>+
>     memset(ctx->ref_subresources, 0, sizeof(UINT) * ctx->max_num_ref);
>     input_args.ReferenceFrames.NumTexture2Ds = ctx->max_num_ref;
>     input_args.ReferenceFrames.ppTexture2Ds  = ctx->ref_resources; @@ -505,7
>+551,7 @@ int ff_d3d12va_common_end_frame(AVCodecContext *avctx,
>AVFrame *frame,
>
>     DX_CHECK(ID3D12VideoDecodeCommandList_Reset(cmd_list,
>command_allocator));
>
>-    num_barrier += d3d12va_update_reference_frames_state(avctx, &barriers[1],
>resource, D3D12_RESOURCE_STATE_COMMON,
>D3D12_RESOURCE_STATE_VIDEO_DECODE_READ);
>+    num_barrier += d3d12va_update_reference_frames_state(avctx,
>+ &barriers[num_barrier], resource, D3D12_RESOURCE_STATE_COMMON,
>+ D3D12_RESOURCE_STATE_VIDEO_DECODE_READ);
>
>     ID3D12VideoDecodeCommandList_ResourceBarrier(cmd_list, num_barrier,
>barriers);
>
>@@ -522,6 +568,10 @@ int ff_d3d12va_common_end_frame(AVCodecContext
>*avctx, AVFrame *frame,
>
>     DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue, f-
>>sync_ctx.fence, ++f->sync_ctx.fence_value));
>
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue,
>output_data->sync_ctx.fence, ++output_data->sync_ctx.fence_value));
>+    }
>+
>     DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue, ctx-
>>sync_ctx.fence, ++ctx->sync_ctx.fence_value));
>
>     ret = d3d12va_discard_helper_objects(avctx, command_allocator, buffer, ctx-
>>sync_ctx.fence_value); diff --git a/libavutil/hwcontext_d3d12va.c
>b/libavutil/hwcontext_d3d12va.c index 6507cf69c1..328827b040 100644
>--- a/libavutil/hwcontext_d3d12va.c
>+++ b/libavutil/hwcontext_d3d12va.c
>@@ -49,6 +49,24 @@ typedef struct D3D12VAFramesContext {
>     ID3D12GraphicsCommandList *command_list;
>     AVD3D12VASyncContext       sync_ctx;
>     UINT                       luma_component_size;
>+
>+    /**
>+     * The Reference-Only feature in DirectX 12 is a memory optimization
>+     * technique designed for video decoding/encoding scenarios.
>+     * This feature requires that reference resources must be allocated
>+     * with the `D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY`
>resource flag.
>+     * Reference textures must also be separated from output textures.
>+     * To correctly support the Reference-Only feature, two parallel resource
>+     * pools must be configured and managed:
>+     * 1. General Resource Pool:
>+     *   - Contains resources used for outputting decoded frames.
>+     *   - Defined in `AVHWFramesContext` and manages the final decoded
>textures.
>+     * 2. Reference-Only Resource Pool:
>+     *   - Dedicated to storing reference frame resources.
>+     *   - Resources created with the
>`D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY`
>+     *     flag are allocated to this pool.
>+     */
>+    AVBufferPool              *pool_reference_only;
> } D3D12VAFramesContext;
>
> typedef struct D3D12VADevicePriv {
>@@ -174,7 +192,8 @@ fail:
>
> static void d3d12va_frames_uninit(AVHWFramesContext *ctx)  {
>-    D3D12VAFramesContext *s = ctx->hwctx;
>+    D3D12VAFramesContext   *s            = ctx->hwctx;
>+    AVD3D12VAFramesContext *frames_hwctx = &s->p;
>
>     D3D12_OBJECT_RELEASE(s->sync_ctx.fence);
>     if (s->sync_ctx.event)
>@@ -185,6 +204,11 @@ static void d3d12va_frames_uninit(AVHWFramesContext
>*ctx)
>     D3D12_OBJECT_RELEASE(s->command_allocator);
>     D3D12_OBJECT_RELEASE(s->command_list);
>     D3D12_OBJECT_RELEASE(s->command_queue);
>+
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        if (s->pool_reference_only)
>+            av_buffer_pool_uninit(&s->pool_reference_only);
>+    }
> }
>
> static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void
>*hwconfig, AVHWFramesConstraints *constraints) @@ -281,6 +305,7 @@ fail:
> static int d3d12va_frames_init(AVHWFramesContext *ctx)  {
>     AVD3D12VAFramesContext *hwctx = ctx->hwctx;
>+    D3D12VAFramesContext   *s     = ctx->hwctx;
>     int i;
>
>     for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { @@ -304,16 +329,43
>@@ static int d3d12va_frames_init(AVHWFramesContext *ctx)
>     if (!ffhwframesctx(ctx)->pool_internal)
>         return AVERROR(ENOMEM);
>
>+    s->pool_reference_only = NULL;
>+
>     return 0;
> }
>
> static int d3d12va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)  {
>     int ret;
>+    D3D12VAFramesContext   *s            = ctx->hwctx;
>+    AVD3D12VAFramesContext *frames_hwctx = &s->p;
>
>-    frame->buf[0] = av_buffer_pool_get(ctx->pool);
>-    if (!frame->buf[0])
>-        return AVERROR(ENOMEM);
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        /*
>+         * for the output texture, temporarily unset
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY
>+         * and D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE
>+        */
>+        D3D12_RESOURCE_FLAGS temp_flags = frames_hwctx->flags;
>+        frames_hwctx->flags &=
>+ ~(D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY |
>+ D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
>+
>+        frame->buf[0] = av_buffer_pool_get(ctx->pool);
>+        if (!frame->buf[0])
>+            return AVERROR(ENOMEM);
>+
>+        if (s->pool_reference_only == NULL) {
>+            s->pool_reference_only = av_buffer_pool_init2(sizeof(AVD3D12VAFrame),
>+                ctx, d3d12va_pool_alloc, NULL);
>+        }
>+
>+        frames_hwctx->flags = temp_flags;
>+        frame->buf[1] = av_buffer_pool_get(s->pool_reference_only);
>+        if (!frame->buf[1])
>+            return AVERROR(ENOMEM);
>+    } else {
>+        frame->buf[0] = av_buffer_pool_get(ctx->pool);
>+        if (!frame->buf[0])
>+            return AVERROR(ENOMEM);
>+    }
>
>     ret = av_image_fill_arrays(frame->data, frame->linesize, NULL,
>                                ctx->sw_format, ctx->width, ctx->height, @@ -322,6 +374,11
>@@ static int d3d12va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
>         return ret;
>
>     frame->data[0] = frame->buf[0]->data;
>+
>+    if (frames_hwctx->flags &
>D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY) {
>+        frame->data[1] = frame->buf[1]->data;
>+    }
>+
>     frame->format  = AV_PIX_FMT_D3D12;
>     frame->width   = ctx->width;
>     frame->height  = ctx->height;
>--
>2.45.2.windows.1
>
>_______________________________________________
>ffmpeg-devel mailing list
>ffmpeg-devel@ffmpeg.org
>https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with
>subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  parent reply	other threads:[~2025-02-10 15:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-30 14:09 Araz Iusubov
2025-01-31  1:22 ` Benjamin Cheng via ffmpeg-devel
2025-02-10 15:18 ` Tong Wu [this message]
2025-02-10 16:34 ` Lynne

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=SY7P300MB0845AA075A9FB23405714100C7F22@SY7P300MB0845.AUSP300.PROD.OUTLOOK.COM \
    --to=wutong1208@outlook.com \
    --cc=Primeadvice@gmail.com \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git