Commit 3eaf97e12c for ffmpeg

commit 3eaf97e12c7e25c22547e78f2c8d06a171b74d83
Author: Steven Xiao <steven.xiao@amd.com>
Date:   Thu Oct 29 07:36:27 2026 -0400

    avutil/hwcontext_d3d12va: support RGB formats and multi-plane transfers

    Generalize the staging-buffer transfer path to use
    ID3D12Device::GetCopyableFootprints() and the format's actual plane
    count instead of hardcoding a two-plane NV12/P010/P012 layout. This
    makes d3d12va_transfer_data() correct for single-plane packed RGB
    formats as well as the existing semi-planar YUV ones.

    Add the packed RGB formats bgra, rgba, x2bgr10 and rgbaf16 to
    supported_formats, so hwupload/hwdownload and other libavutil
    consumers can allocate and transfer d3d12 frames in those formats.

    Signed-off-by: younengxiao <steven.xiao@amd.com>

diff --git a/libavutil/hwcontext_d3d12va.c b/libavutil/hwcontext_d3d12va.c
index f9d1721cd6..e7dc733bac 100644
--- a/libavutil/hwcontext_d3d12va.c
+++ b/libavutil/hwcontext_d3d12va.c
@@ -48,7 +48,13 @@ typedef struct D3D12VAFramesContext {
     ID3D12CommandAllocator    *command_allocator;
     ID3D12GraphicsCommandList *command_list;
     AVD3D12VASyncContext       sync_ctx;
-    UINT                       luma_component_size;
+
+    /* Per-plane copy layout for the staging buffer, computed once per
+     * frames context from ID3D12Device::GetCopyableFootprints(). */
+    D3D12_PLACED_SUBRESOURCE_FOOTPRINT plane_layouts[4];
+    UINT                       plane_count;
+    UINT64                     staging_buffer_size;
+
     int                        nb_surfaces_used;
 } D3D12VAFramesContext;

@@ -68,9 +74,13 @@ static const struct {
     DXGI_FORMAT d3d_format;
     enum AVPixelFormat pix_fmt;
 } supported_formats[] = {
-    { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
-    { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
-    { DXGI_FORMAT_P016, AV_PIX_FMT_P012 },
+    { DXGI_FORMAT_NV12,               AV_PIX_FMT_NV12    },
+    { DXGI_FORMAT_P010,               AV_PIX_FMT_P010    },
+    { DXGI_FORMAT_P016,               AV_PIX_FMT_P012    },
+    { DXGI_FORMAT_B8G8R8A8_UNORM,     AV_PIX_FMT_BGRA    },
+    { DXGI_FORMAT_R8G8B8A8_UNORM,     AV_PIX_FMT_RGBA    },
+    { DXGI_FORMAT_R10G10B10A2_UNORM,  AV_PIX_FMT_X2BGR10 },
+    { DXGI_FORMAT_R16G16B16A16_FLOAT, AV_PIX_FMT_RGBAF16 },
 };

 static void d3d12va_default_lock(void *ctx)
@@ -114,7 +124,7 @@ static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_
     D3D12_RESOURCE_DESC desc = {
         .Dimension          = D3D12_RESOURCE_DIMENSION_BUFFER,
         .Alignment          = 0,
-        .Width              = s->luma_component_size + (s->luma_component_size >> 1),
+        .Width              = s->staging_buffer_size,
         .Height             = 1,
         .DepthOrArraySize   = 1,
         .MipLevels          = 1,
@@ -133,11 +143,48 @@ static int d3d12va_create_staging_buffer_resource(AVHWFramesContext *ctx, D3D12_
     return 0;
 }

-static int d3d12va_create_helper_objects(AVHWFramesContext *ctx)
+static int d3d12va_get_plane_layouts(AVHWFramesContext *ctx)
 {
     AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
     D3D12VAFramesContext   *s            = ctx->hwctx;
     AVD3D12VAFramesContext *frames_hwctx = &s->p;
+    D3D12_FEATURE_DATA_FORMAT_INFO format_info = { .Format = frames_hwctx->format };
+    HRESULT hr;
+
+    D3D12_RESOURCE_DESC desc = {
+        .Dimension        = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+        .Alignment        = 0,
+        .Width            = ctx->width,
+        .Height           = ctx->height,
+        .DepthOrArraySize = 1,
+        .MipLevels        = 1,
+        .Format           = frames_hwctx->format,
+        .SampleDesc       = { .Count = 1, .Quality = 0 },
+        .Layout           = D3D12_TEXTURE_LAYOUT_UNKNOWN,
+        .Flags            = D3D12_RESOURCE_FLAG_NONE,
+    };
+
+    hr = ID3D12Device_CheckFeatureSupport(device_hwctx->device, D3D12_FEATURE_FORMAT_INFO,
+                                          &format_info, sizeof(format_info));
+    if (FAILED(hr) || !format_info.PlaneCount ||
+        format_info.PlaneCount > FF_ARRAY_ELEMS(s->plane_layouts)) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to query plane count for DXGI format %d\n", frames_hwctx->format);
+        return AVERROR_EXTERNAL;
+    }
+
+    s->plane_count = format_info.PlaneCount;
+
+    ID3D12Device_GetCopyableFootprints(device_hwctx->device, &desc, 0, s->plane_count, 0,
+                                       s->plane_layouts, NULL, NULL, &s->staging_buffer_size);
+
+    return 0;
+}
+
+static int d3d12va_create_helper_objects(AVHWFramesContext *ctx)
+{
+    AVD3D12VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
+    D3D12VAFramesContext   *s            = ctx->hwctx;
+    int ret;

     D3D12_COMMAND_QUEUE_DESC queue_desc = {
         .Type     = D3D12_COMMAND_LIST_TYPE_COPY,
@@ -145,8 +192,9 @@ static int d3d12va_create_helper_objects(AVHWFramesContext *ctx)
         .NodeMask = 0,
     };

-    s->luma_component_size = FFALIGN(ctx->width * (frames_hwctx->format != DXGI_FORMAT_NV12 ? 2 : 1),
-                                     D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * ctx->height;
+    ret = d3d12va_get_plane_layouts(ctx);
+    if (ret < 0)
+        return ret;

     DX_CHECK(ID3D12Device_CreateFence(device_hwctx->device, 0, D3D12_FENCE_FLAG_NONE,
                                       &IID_ID3D12Fence, (void **)&s->sync_ctx.fence));
@@ -439,7 +487,6 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
 {
     AVD3D12VADeviceContext *hwctx        = ctx->device_ctx->hwctx;
     D3D12VAFramesContext   *s            = ctx->hwctx;
-    AVD3D12VAFramesContext *frames_hwctx = &s->p;

     int ret;
     int download = src->format == AV_PIX_FMT_D3D12;
@@ -448,36 +495,17 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,

     AVD3D12VAFrame *f = (AVD3D12VAFrame *)frame->data[0];
     ID3D12Resource *texture = (ID3D12Resource *)f->texture;
+    D3D12_RESOURCE_DESC texture_desc;
+    UINT array_size;

     uint8_t *mapped_data;
-    uint8_t *data[4];
-    int linesizes[4];
+    uint8_t *data[4]     = { NULL };
+    int linesizes[4]     = { 0 };

-    D3D12_TEXTURE_COPY_LOCATION staging_y_location  = { 0 };
-    D3D12_TEXTURE_COPY_LOCATION staging_uv_location = { 0 };
+    texture->lpVtbl->GetDesc(texture, &texture_desc);
+    array_size = texture_desc.DepthOrArraySize;

-    D3D12_TEXTURE_COPY_LOCATION texture_y_location = {
-        .pResource        = texture,
-        .Type             = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
-        .SubresourceIndex = 0,
-    };
-
-    D3D12_TEXTURE_COPY_LOCATION texture_uv_location = {
-        .pResource        = texture,
-        .Type             = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
-        .SubresourceIndex = 1,
-    };
-
-    D3D12_RESOURCE_BARRIER barrier = {
-        .Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
-        .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
-        .Transition = {
-            .pResource   = texture,
-            .StateBefore = D3D12_RESOURCE_STATE_COMMON,
-            .StateAfter  = download ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_COPY_DEST,
-            .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
-        },
-    };
+    D3D12_RESOURCE_BARRIER barriers[4];

     if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
         return AVERROR(EINVAL);
@@ -490,39 +518,21 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
             goto fail;
     }

-    for (int i = 0; i < 4; i++)
-        linesizes[i] = FFALIGN(frame->width * (frames_hwctx->format != DXGI_FORMAT_NV12 ? 2 : 1),
-                               D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
-
-    staging_y_location = (D3D12_TEXTURE_COPY_LOCATION) {
-        .Type      = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
-        .PlacedFootprint = {
-            .Offset = 0,
-            .Footprint = {
-                .Format   = frames_hwctx->format != DXGI_FORMAT_NV12 ?
-                                                    DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM,
-                .Width    = ctx->width,
-                .Height   = ctx->height,
-                .Depth    = 1,
-                .RowPitch = linesizes[0],
-            },
-        },
-    };
-
-    staging_uv_location = (D3D12_TEXTURE_COPY_LOCATION) {
-        .Type      = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
-        .PlacedFootprint = {
-            .Offset = s->luma_component_size,
-            .Footprint = {
-                .Format   = frames_hwctx->format != DXGI_FORMAT_NV12 ?
-                                                    DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM,
-                .Width    = ctx->width  >> 1,
-                .Height   = ctx->height >> 1,
-                .Depth    = 1,
-                .RowPitch = linesizes[0],
+    for (UINT i = 0; i < s->plane_count; i++)
+        linesizes[i] = s->plane_layouts[i].Footprint.RowPitch;
+
+    for (UINT i = 0; i < s->plane_count; i++) {
+        barriers[i] = (D3D12_RESOURCE_BARRIER) {
+            .Type  = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
+            .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
+            .Transition = {
+                .pResource   = texture,
+                .StateBefore = D3D12_RESOURCE_STATE_COMMON,
+                .StateAfter  = download ? D3D12_RESOURCE_STATE_COPY_SOURCE : D3D12_RESOURCE_STATE_COPY_DEST,
+                .Subresource = f->subresource_index + i * array_size,
             },
-        },
-    };
+        };
+    }

     DX_CHECK(ID3D12CommandAllocator_Reset(s->command_allocator));

@@ -537,21 +547,30 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
             }
         }

-        staging_y_location.pResource = staging_uv_location.pResource = s->staging_download_buffer;
-
-        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
-
-        ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
-                                                    &staging_y_location, 0, 0, 0,
-                                                    &texture_y_location, NULL);
-
-        ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
-                                                    &staging_uv_location, 0, 0, 0,
-                                                    &texture_uv_location, NULL);
+        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, s->plane_count, barriers);
+
+        for (UINT i = 0; i < s->plane_count; i++) {
+            D3D12_TEXTURE_COPY_LOCATION staging_location = {
+                .pResource       = s->staging_download_buffer,
+                .Type            = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
+                .PlacedFootprint = s->plane_layouts[i],
+            };
+            D3D12_TEXTURE_COPY_LOCATION texture_location = {
+                .pResource        = texture,
+                .Type             = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
+                .SubresourceIndex = f->subresource_index + i * array_size,
+            };
+
+            ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
+                                                        &staging_location, 0, 0, 0,
+                                                        &texture_location, NULL);
+        }

-        barrier.Transition.StateBefore = barrier.Transition.StateAfter;
-        barrier.Transition.StateAfter  = D3D12_RESOURCE_STATE_COMMON;
-        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
+        for (UINT i = 0; i < s->plane_count; i++) {
+            barriers[i].Transition.StateBefore = barriers[i].Transition.StateAfter;
+            barriers[i].Transition.StateAfter  = D3D12_RESOURCE_STATE_COMMON;
+        }
+        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, s->plane_count, barriers);

         DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));

@@ -564,7 +583,8 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
             goto fail;

         DX_CHECK(ID3D12Resource_Map(s->staging_download_buffer, 0, NULL, (void **)&mapped_data));
-        av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
+        for (UINT i = 0; i < s->plane_count; i++)
+            data[i] = mapped_data + s->plane_layouts[i].Offset;

         av_image_copy2(dst->data, dst->linesize, data, linesizes,
                        ctx->sw_format, ctx->width, ctx->height);
@@ -579,29 +599,39 @@ static int d3d12va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
             }
         }

-        staging_y_location.pResource = staging_uv_location.pResource = s->staging_upload_buffer;
-
         DX_CHECK(ID3D12Resource_Map(s->staging_upload_buffer, 0, NULL, (void **)&mapped_data));
-        av_image_fill_pointers(data, ctx->sw_format, ctx->height, mapped_data, linesizes);
+        for (UINT i = 0; i < s->plane_count; i++)
+            data[i] = mapped_data + s->plane_layouts[i].Offset;

         av_image_copy2(data, linesizes, src->data, src->linesize,
                        ctx->sw_format, ctx->width, ctx->height);

         ID3D12Resource_Unmap(s->staging_upload_buffer, 0, NULL);

-        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
-
-        ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
-                                                    &texture_y_location, 0, 0, 0,
-                                                    &staging_y_location, NULL);
-
-        ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
-                                                    &texture_uv_location, 0, 0, 0,
-                                                    &staging_uv_location, NULL);
+        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, s->plane_count, barriers);
+
+        for (UINT i = 0; i < s->plane_count; i++) {
+            D3D12_TEXTURE_COPY_LOCATION staging_location = {
+                .pResource       = s->staging_upload_buffer,
+                .Type            = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
+                .PlacedFootprint = s->plane_layouts[i],
+            };
+            D3D12_TEXTURE_COPY_LOCATION texture_location = {
+                .pResource        = texture,
+                .Type             = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
+                .SubresourceIndex = f->subresource_index + i * array_size,
+            };
+
+            ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
+                                                        &texture_location, 0, 0, 0,
+                                                        &staging_location, NULL);
+        }

-        barrier.Transition.StateBefore = barrier.Transition.StateAfter;
-        barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
-        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
+        for (UINT i = 0; i < s->plane_count; i++) {
+            barriers[i].Transition.StateBefore = barriers[i].Transition.StateAfter;
+            barriers[i].Transition.StateAfter  = D3D12_RESOURCE_STATE_COMMON;
+        }
+        ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, s->plane_count, barriers);

         DX_CHECK(ID3D12GraphicsCommandList_Close(s->command_list));