The branch, master has been updated
       via  c2ce387385996c4e6824116931930b08cfcaecc9 (commit)
      from  6ce02bcc3acbfcd48052fd21456722f4d35cda8e (commit)


- Log -----------------------------------------------------------------
commit c2ce387385996c4e6824116931930b08cfcaecc9
Author:     Araz Iusubov <[email protected]>
AuthorDate: Mon Aug 11 12:48:47 2025 +0200
Commit:     Araz Iusubov <[email protected]>
CommitDate: Wed Sep 3 11:56:06 2025 +0200

    avcodec/d3d12va_encode: texture array support for HEVC
    
    This patch adds support for the texture array feature
    used by AMD boards in the D3D12 HEVC encoder.
    In texture array mode, a single texture array is shared for all
    reference and reconstructed pictures using different subresources.
    The implementation ensures compatibility
    and has been successfully tested on AMD, Intel, and NVIDIA GPUs.

diff --git a/doc/APIchanges b/doc/APIchanges
index a3626d3c20..d69aaf2215 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,14 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-09-xx - xxxxxxxxxx - lavu 60.12.100 - hwcontext_d3d12va.h
+  Add support for texture array mode AVD3D12VAFrame.subresource_index,
+  AVD3D12VAFramesContext.texture_array
+  Add enum AVD3D12VAFrameFlags to define the behaviours of frame allocation.
+  Renanme AVD3D12VAFramesContext.flags to 
AVD3D12VAFramesContext.resource_flags.
+  Add flags to AVD3D12VAFramesContext
+  Add flags to AVD3D12VAFrame
+
 2025-09-xx - xxxxxxxxxx - lavfi 11.8.100 - buffersrc.h
   Add AVBufferSrcParameters.alpha_mode.
 
diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c
index 008b0ddc2a..f34605ec41 100644
--- a/libavcodec/d3d12va_encode.c
+++ b/libavcodec/d3d12va_encode.c
@@ -191,7 +191,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
     D3D12VAEncodeContext       *ctx = avctx->priv_data;
     D3D12VAEncodePicture       *pic = base_pic->priv;
-    AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx;
+    AVD3D12VAFramesContext     *frames_hwctx = base_ctx->input_frames->hwctx;
     int err, i, j;
     HRESULT hr;
     char data[MAX_PARAM_BUFFER_SIZE];
@@ -201,6 +201,8 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list;
     D3D12_RESOURCE_BARRIER barriers[32] = { 0 };
     D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 };
+    int barriers_ref_index = 0;
+    D3D12_RESOURCE_BARRIER *barriers_ref = NULL;
 
     D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
         .SequenceControlDesc = {
@@ -268,6 +270,8 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n",
            pic->recon_surface->texture);
 
+    pic->subresource_index = ctx->is_texture_array ? 
pic->recon_surface->subresource_index : 0;
+
     pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool);
     if (!pic->output_buffer_ref) {
         err = AVERROR(ENOMEM);
@@ -324,11 +328,28 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
             goto fail;
         }
 
+        if (ctx->is_texture_array) {
+            d3d12_refs.pSubresources = av_calloc(d3d12_refs.NumTexture2Ds,
+                                                 
sizeof(*d3d12_refs.pSubresources));
+            if (!d3d12_refs.pSubresources) {
+                err = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
+
         i = 0;
-        for (j = 0; j < base_pic->nb_refs[0]; j++)
-            d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture 
*)base_pic->refs[0][j]->priv)->recon_surface->texture;
-        for (j = 0; j < base_pic->nb_refs[1]; j++)
-            d3d12_refs.ppTexture2Ds[i++] = ((D3D12VAEncodePicture 
*)base_pic->refs[1][j]->priv)->recon_surface->texture;
+        for (j = 0; j < base_pic->nb_refs[0]; j++) {
+            d3d12_refs.ppTexture2Ds[i]  = ((D3D12VAEncodePicture 
*)base_pic->refs[0][j]->priv)->recon_surface->texture;
+            if (ctx->is_texture_array)
+                d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture 
*)base_pic->refs[0][j]->priv)->subresource_index;
+            i++;
+        }
+        for (j = 0; j < base_pic->nb_refs[1]; j++) {
+            d3d12_refs.ppTexture2Ds[i]  = ((D3D12VAEncodePicture 
*)base_pic->refs[1][j]->priv)->recon_surface->texture;
+            if (ctx->is_texture_array)
+                d3d12_refs.pSubresources[i] = ((D3D12VAEncodePicture 
*)base_pic->refs[1][j]->priv)->subresource_index;
+            i++;
+        }
     }
 
     input_args.PictureControlDesc.IntraRefreshFrameIndex  = 0;
@@ -342,7 +363,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     output_args.Bitstream.pBuffer                                    = 
pic->output_buffer;
     output_args.Bitstream.FrameStartOffset                           = 
pic->aligned_header_size;
     output_args.ReconstructedPicture.pReconstructedPicture           = 
pic->recon_surface->texture;
-    output_args.ReconstructedPicture.ReconstructedPictureSubresource = 0;
+    output_args.ReconstructedPicture.ReconstructedPictureSubresource = 
ctx->is_texture_array ? pic->subresource_index : 0;
     output_args.EncoderOutputMetadata.pBuffer                        = 
pic->encoded_metadata;
     output_args.EncoderOutputMetadata.Offset                         = 0;
 
@@ -368,52 +389,89 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
         goto fail;
     }
 
-#define TRANSITION_BARRIER(res, before, after)                      \
+#define TRANSITION_BARRIER(res, subres, before, after)              \
     (D3D12_RESOURCE_BARRIER) {                                      \
         .Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,            \
         .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,                  \
         .Transition = {                                             \
             .pResource   = res,                                     \
-            .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, \
+            .Subresource = subres,                                  \
             .StateBefore = before,                                  \
             .StateAfter  = after,                                   \
         },                                                          \
     }
 
     barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_COMMON,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
     barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_COMMON,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
-    barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
-                                     D3D12_RESOURCE_STATE_COMMON,
-                                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
-    barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
+    barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_COMMON,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
-    barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
+    barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_COMMON,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
 
-    ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
+    ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
 
-    if (d3d12_refs.NumTexture2Ds) {
-        D3D12_RESOURCE_BARRIER refs_barriers[3];
-
-        for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
-            refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
-                                                  D3D12_RESOURCE_STATE_COMMON,
-                                                  
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
-
-        ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 
d3d12_refs.NumTexture2Ds,
-                                                      refs_barriers);
+    if (ctx->is_texture_array)
+        barriers_ref = av_calloc(base_ctx->recon_frames->initial_pool_size * 
ctx->plane_count,
+                                 sizeof(D3D12_RESOURCE_BARRIER));
+    else
+        barriers_ref = av_calloc(MAX_DPB_SIZE, sizeof(D3D12_RESOURCE_BARRIER));
+
+    if (ctx->is_texture_array) {
+        D3D12_RESOURCE_DESC references_tex_array_desc = { 0 };
+        
pic->recon_surface->texture->lpVtbl->GetDesc(pic->recon_surface->texture, 
&references_tex_array_desc);
+
+        for (uint32_t reference_subresource = 0; reference_subresource < 
references_tex_array_desc.DepthOrArraySize;
+             reference_subresource++) {
+
+            uint32_t array_size = references_tex_array_desc.DepthOrArraySize;
+            uint32_t mip_slice = reference_subresource % 
references_tex_array_desc.MipLevels;
+            uint32_t array_slice = (reference_subresource / 
references_tex_array_desc.MipLevels) % array_size;
+
+            for (uint32_t plane_slice = 0; plane_slice < ctx->plane_count; 
plane_slice++) {
+                uint32_t outputSubresource = mip_slice + array_slice * 
references_tex_array_desc.MipLevels +
+                                             plane_slice * 
references_tex_array_desc.MipLevels * array_size;
+                if (reference_subresource == pic->subresource_index) {
+                    barriers_ref[barriers_ref_index++] = 
TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
+                                                                            
D3D12_RESOURCE_STATE_COMMON,
+                                                                            
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
+                } else {
+                    barriers_ref[barriers_ref_index++] = 
TRANSITION_BARRIER(pic->recon_surface->texture, outputSubresource,
+                                                                            
D3D12_RESOURCE_STATE_COMMON,
+                                                                            
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
+                }
+            }
+        }
+    } else {
+        barriers_ref[barriers_ref_index++] = 
TRANSITION_BARRIER(pic->recon_surface->texture,
+                                                                
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
+                                                                
D3D12_RESOURCE_STATE_COMMON,
+                                                                
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
+
+        if (d3d12_refs.NumTexture2Ds) {
+            for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
+                barriers_ref[barriers_ref_index++] = 
TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
+                                                                        
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
+                                                                        
D3D12_RESOURCE_STATE_COMMON,
+                                                                        
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
+        }
     }
+    ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 
barriers_ref_index, barriers_ref);
 
     ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, 
ctx->encoder_heap,
                                               &input_args, &output_args);
 
     barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
 
@@ -421,35 +479,32 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
 
     ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, 
&input_metadata, &output_metadata);
 
-    if (d3d12_refs.NumTexture2Ds) {
-        D3D12_RESOURCE_BARRIER refs_barriers[3];
-
-        for (i = 0; i < d3d12_refs.NumTexture2Ds; i++)
-            refs_barriers[i] = TRANSITION_BARRIER(d3d12_refs.ppTexture2Ds[i],
-                                                  
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
-                                                  D3D12_RESOURCE_STATE_COMMON);
+    if (barriers_ref_index > 0) {
+        for (i = 0; i < barriers_ref_index; i++)
+            FFSWAP(D3D12_RESOURCE_STATES, 
barriers_ref[i].Transition.StateBefore, barriers_ref[i].Transition.StateAfter);
 
-        ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 
d3d12_refs.NumTexture2Ds,
-                                                      refs_barriers);
+        ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 
barriers_ref_index,
+                                                      barriers_ref);
     }
 
     barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
                                      D3D12_RESOURCE_STATE_COMMON);
     barriers[1] = TRANSITION_BARRIER(pic->output_buffer,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
                                      D3D12_RESOURCE_STATE_COMMON);
-    barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture,
-                                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
-                                     D3D12_RESOURCE_STATE_COMMON);
-    barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
+    barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
                                      D3D12_RESOURCE_STATE_COMMON);
-    barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata,
+    barriers[3] = TRANSITION_BARRIER(pic->resolved_metadata,
+                                     D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
                                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
                                      D3D12_RESOURCE_STATE_COMMON);
 
-    ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers);
+    ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 4, barriers);
 
     hr = ID3D12VideoEncodeCommandList2_Close(cmd_list);
     if (FAILED(hr)) {
@@ -488,6 +543,12 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     if (d3d12_refs.ppTexture2Ds)
         av_freep(&d3d12_refs.ppTexture2Ds);
 
+    if (ctx->is_texture_array && d3d12_refs.pSubresources)
+        av_freep(&d3d12_refs.pSubresources);
+
+    if (barriers_ref)
+        av_freep(&barriers_ref);
+
     return 0;
 
 fail:
@@ -497,6 +558,12 @@ fail:
     if (d3d12_refs.ppTexture2Ds)
         av_freep(&d3d12_refs.ppTexture2Ds);
 
+    if (ctx->is_texture_array && d3d12_refs.pSubresources)
+        av_freep(&d3d12_refs.pSubresources);
+
+    if (barriers_ref)
+        av_freep(&barriers_ref);
+
     if (ctx->codec->free_picture_params)
         ctx->codec->free_picture_params(pic);
 
@@ -1354,6 +1421,7 @@ fail:
 static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx)
 {
     FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+    D3D12VAEncodeContext       *ctx = avctx->priv_data;
     AVD3D12VAFramesContext *hwctx;
     enum AVPixelFormat recon_format;
     int err;
@@ -1374,8 +1442,12 @@ static int 
d3d12va_encode_create_recon_frames(AVCodecContext *avctx)
     base_ctx->recon_frames->width     = base_ctx->surface_width;
     base_ctx->recon_frames->height    = base_ctx->surface_height;
 
-    hwctx->flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
-                   D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+    hwctx->resource_flags = D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
+                            D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+    if (ctx->is_texture_array) {
+        base_ctx->recon_frames->initial_pool_size = MAX_DPB_SIZE + 1;
+        hwctx->flags |= AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY;
+    }
 
     err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
     if (err < 0) {
@@ -1409,6 +1481,7 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
     FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
     D3D12VAEncodeContext       *ctx = avctx->priv_data;
     D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT support = { 0 };
+    D3D12_FEATURE_DATA_FORMAT_INFO format_info = { 0 };
     int err;
     HRESULT hr;
 
@@ -1444,6 +1517,15 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
         goto fail;
     }
 
+    format_info.Format = ((AVD3D12VAFramesContext 
*)base_ctx->input_frames->hwctx)->format;
+    if (FAILED(ID3D12VideoDevice_CheckFeatureSupport(ctx->hwctx->device, 
D3D12_FEATURE_FORMAT_INFO,
+        &format_info, sizeof(format_info)))) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to query format plane count: 
0x%x\n", hr);
+        err = AVERROR_EXTERNAL;
+        goto fail;
+    }
+    ctx->plane_count = format_info.PlaneCount;
+
     err = d3d12va_encode_set_profile(avctx);
     if (err < 0)
         goto fail;
@@ -1471,10 +1553,6 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
     if (err < 0)
         goto fail;
 
-    err = d3d12va_encode_create_recon_frames(avctx);
-    if (err < 0)
-        goto fail;
-
     err = d3d12va_encode_prepare_output_buffers(avctx);
     if (err < 0)
         goto fail;
@@ -1500,6 +1578,10 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
             goto fail;
     }
 
+    err = d3d12va_encode_create_recon_frames(avctx);
+    if (err < 0)
+        goto fail;
+
     base_ctx->output_delay = base_ctx->b_per_p;
     base_ctx->decode_delay = base_ctx->max_b_depth;
 
diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h
index 8af5554626..5bd1eedb7f 100644
--- a/libavcodec/d3d12va_encode.h
+++ b/libavcodec/d3d12va_encode.h
@@ -52,6 +52,8 @@ typedef struct D3D12VAEncodePicture {
     ID3D12Resource *encoded_metadata;
     ID3D12Resource *resolved_metadata;
 
+    int            subresource_index;
+
     D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl;
 
     int             fence_value;
@@ -194,6 +196,16 @@ typedef struct D3D12VAEncodeContext {
      */
     AVBufferPool *output_buffer_pool;
 
+    /**
+     * Flag indicates if the HW is texture array mode.
+     */
+    int is_texture_array;
+
+    /**
+     * The number of planes in the input DXGI FORMAT.
+     */
+    int plane_count;
+
     /**
      * D3D12 video encoder.
      */
diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c
index 4f4dda1f8f..01e5b4cb4c 100644
--- a/libavcodec/d3d12va_encode_hevc.c
+++ b/libavcodec/d3d12va_encode_hevc.c
@@ -279,9 +279,8 @@ static int 
d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx)
     }
 
     if (support.SupportFlags & 
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) {
-        av_log(avctx, AV_LOG_ERROR, "D3D12 video encode on this device 
requires texture array support, "
-               "but it's not implemented.\n");
-        return AVERROR_PATCHWELCOME;
+        ctx->is_texture_array = 1;
+        av_log(avctx, AV_LOG_DEBUG, "D3D12 video encode on this device uses 
texture array mode.\n");
     }
 
     desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
diff --git a/libavutil/hwcontext_d3d12va.c b/libavutil/hwcontext_d3d12va.c
index 6507cf69c1..9368341d6d 100644
--- a/libavutil/hwcontext_d3d12va.c
+++ b/libavutil/hwcontext_d3d12va.c
@@ -49,6 +49,7 @@ typedef struct D3D12VAFramesContext {
     ID3D12GraphicsCommandList *command_list;
     AVD3D12VASyncContext       sync_ctx;
     UINT                       luma_component_size;
+    int                        nb_surfaces_used;
 } D3D12VAFramesContext;
 
 typedef struct D3D12VADevicePriv {
@@ -174,7 +175,8 @@ fail:
 
 static void d3d12va_frames_uninit(AVHWFramesContext *ctx)
 {
-    D3D12VAFramesContext *s = ctx->hwctx;
+    D3D12VAFramesContext   *s     = ctx->hwctx;
+    AVD3D12VAFramesContext *hwctx = ctx->hwctx;
 
     D3D12_OBJECT_RELEASE(s->sync_ctx.fence);
     if (s->sync_ctx.event)
@@ -185,6 +187,9 @@ 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 (hwctx->texture_array)
+        D3D12_OBJECT_RELEASE(hwctx->texture_array);
 }
 
 static int d3d12va_frames_get_constraints(AVHWDeviceContext *ctx, const void 
*hwconfig, AVHWFramesConstraints *constraints)
@@ -220,7 +225,9 @@ static void free_texture(void *opaque, uint8_t *data)
 {
     AVD3D12VAFrame *frame = (AVD3D12VAFrame *)data;
 
-    D3D12_OBJECT_RELEASE(frame->texture);
+    if (!(frame->flags & AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY))
+        D3D12_OBJECT_RELEASE(frame->texture);
+
     D3D12_OBJECT_RELEASE(frame->sync_ctx.fence);
     if (frame->sync_ctx.event)
         CloseHandle(frame->sync_ctx.event);
@@ -228,6 +235,42 @@ static void free_texture(void *opaque, uint8_t *data)
     av_freep(&data);
 }
 
+static AVBufferRef *d3d12va_pool_alloc_texture_array(AVHWFramesContext *ctx)
+{
+    AVD3D12VAFrame         *frame  = av_mallocz(sizeof(*frame));
+    D3D12VAFramesContext   *s     = ctx->hwctx;
+    AVD3D12VAFramesContext *hwctx = ctx->hwctx;
+    AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
+    AVBufferRef *buf;
+
+    frame->flags |= AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY;
+
+    DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, 
D3D12_FENCE_FLAG_NONE,
+                                      &IID_ID3D12Fence, (void 
**)&frame->sync_ctx.fence));
+    frame->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!frame->sync_ctx.event)
+        goto fail;
+
+    if (s->nb_surfaces_used >= ctx->initial_pool_size) {
+        av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
+        goto fail;
+    }
+
+    frame->texture = hwctx->texture_array;
+    frame->subresource_index = s->nb_surfaces_used;
+
+    buf = av_buffer_create((uint8_t *)frame, sizeof(*frame), free_texture, 
NULL, 0);
+
+    if (!buf)
+        goto fail;
+
+    s->nb_surfaces_used++;
+    return buf;
+fail:
+    free_texture(NULL, (uint8_t *)frame);
+    return NULL;
+}
+
 static AVBufferRef *d3d12va_pool_alloc(void *opaque, size_t size)
 {
     AVHWFramesContext      *ctx          = (AVHWFramesContext *)opaque;
@@ -236,6 +279,10 @@ static AVBufferRef *d3d12va_pool_alloc(void *opaque, 
size_t size)
 
     AVBufferRef *buf;
     AVD3D12VAFrame *frame;
+
+    if (ctx->initial_pool_size > 0 && hwctx->flags & 
AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY)
+        return d3d12va_pool_alloc_texture_array(ctx);
+
     D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
     D3D12_RESOURCE_DESC desc = {
         .Dimension        = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
@@ -247,7 +294,7 @@ static AVBufferRef *d3d12va_pool_alloc(void *opaque, size_t 
size)
         .Format           = hwctx->format,
         .SampleDesc       = {.Count = 1, .Quality = 0 },
         .Layout           = D3D12_TEXTURE_LAYOUT_UNKNOWN,
-        .Flags            = hwctx->flags,
+        .Flags            = hwctx->resource_flags,
     };
 
     frame = av_mallocz(sizeof(AVD3D12VAFrame));
@@ -278,6 +325,34 @@ fail:
     return NULL;
 }
 
+static int d3d12va_texture_array_init(AVHWFramesContext *ctx)
+{
+    AVD3D12VAFramesContext *hwctx        = ctx->hwctx;
+    AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
+
+    D3D12_HEAP_PROPERTIES props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
+
+    D3D12_RESOURCE_DESC desc = {
+        .Dimension        = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+        .Alignment        = 0,
+        .Width            = ctx->width,
+        .Height           = ctx->height,
+        .DepthOrArraySize = ctx->initial_pool_size,
+        .MipLevels        = 1,
+        .Format           = hwctx->format,
+        .SampleDesc       = {.Count = 1, .Quality = 0 },
+        .Layout           = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        .Flags            = hwctx->resource_flags,
+    };
+
+    if (FAILED(ID3D12Device_CreateCommittedResource(device_hwctx->device, 
&props, D3D12_HEAP_FLAG_NONE, &desc,
+        D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void 
**)&hwctx->texture_array))) {
+        av_log(ctx, AV_LOG_ERROR, "Could not create the texture array\n");
+        return AVERROR(EINVAL);
+    }
+    return 0;
+}
+
 static int d3d12va_frames_init(AVHWFramesContext *ctx)
 {
     AVD3D12VAFramesContext *hwctx = ctx->hwctx;
@@ -298,6 +373,12 @@ static int d3d12va_frames_init(AVHWFramesContext *ctx)
         return AVERROR(EINVAL);
     }
 
+    if (ctx->initial_pool_size > 0 && hwctx->flags & 
AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY) {
+        int err = d3d12va_texture_array_init(ctx);
+        if (err < 0)
+            return err;
+    }
+
     ffhwframesctx(ctx)->pool_internal = 
av_buffer_pool_init2(sizeof(AVD3D12VAFrame),
         ctx, d3d12va_pool_alloc, NULL);
 
diff --git a/libavutil/hwcontext_d3d12va.h b/libavutil/hwcontext_d3d12va.h
index 212a6a6146..1530de8b3c 100644
--- a/libavutil/hwcontext_d3d12va.h
+++ b/libavutil/hwcontext_d3d12va.h
@@ -99,6 +99,18 @@ typedef struct AVD3D12VASyncContext {
     uint64_t fence_value;
 } AVD3D12VASyncContext;
 
+/**
+ * Define the behaviours of frame allocation.
+ */
+typedef enum AVD3D12VAFrameFlags {
+    AV_D3D12VA_FRAME_FLAG_NONE = 0,
+
+    /**
+     * Indicates that frame data should be allocated using a texture array 
resource.
+     */
+    AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY = (1 << 1),
+} AVD3D12VAFrameFlags;
+
 /**
  * @brief D3D12VA frame descriptor for pool allocation.
  *
@@ -111,12 +123,26 @@ typedef struct AVD3D12VAFrame {
      */
     ID3D12Resource *texture;
 
+    /**
+     * Index of the subresource within the texture.
+     *
+     * In texture array mode, this specifies the array slice index.
+     * When texture array mode is not used, this value is always 0.
+     */
+    int subresource_index;
+
     /**
      * The sync context for the texture
      *
      * @see: 
https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-overview#directx-12-fences
      */
     AVD3D12VASyncContext sync_ctx;
+
+    /**
+     * A combination of AVD3D12VAFrameFlags.
+     * Set by AVD3D12VAFramesContext.
+     */
+    AVD3D12VAFrameFlags flags;
 } AVD3D12VAFrame;
 
 /**
@@ -136,7 +162,20 @@ typedef struct AVD3D12VAFramesContext {
      *
      * @see 
https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_flags
      */
-    D3D12_RESOURCE_FLAGS flags;
+    D3D12_RESOURCE_FLAGS resource_flags;
+
+    /**
+     * In texture array mode, the D3D12 uses the same texture array 
(resource)for all
+     * pictures.
+     */
+    ID3D12Resource *texture_array;
+
+    /**
+     * A combination of AVD3D12VAFrameFlags. Unless AV_D3D12VA_FRAME_FLAG_NONE 
is set,
+     * autodetected flags will be OR'd based on the device and frame features 
during
+     * av_hwframe_ctx_init().
+     */
+    AVD3D12VAFrameFlags flags;
 } AVD3D12VAFramesContext;
 
 #endif /* AVUTIL_HWCONTEXT_D3D12VA_H */

-----------------------------------------------------------------------

Summary of changes:
 doc/APIchanges                   |   8 ++
 libavcodec/d3d12va_encode.c      | 172 +++++++++++++++++++++++++++++----------
 libavcodec/d3d12va_encode.h      |  12 +++
 libavcodec/d3d12va_encode_hevc.c |   5 +-
 libavutil/hwcontext_d3d12va.c    |  87 +++++++++++++++++++-
 libavutil/hwcontext_d3d12va.h    |  41 +++++++++-
 6 files changed, 273 insertions(+), 52 deletions(-)


hooks/post-receive
-- 

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to