This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 3eaf97e12c7e25c22547e78f2c8d06a171b74d83 Author: Steven Xiao <[email protected]> AuthorDate: Thu Oct 29 07:36:27 2026 -0400 Commit: Steven Xiao <[email protected]> CommitDate: Mon Nov 2 12:35:20 2026 +0000 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 <[email protected]> --- libavutil/hwcontext_d3d12va.c | 214 ++++++++++++++++++++++++------------------ 1 file changed, 122 insertions(+), 92 deletions(-) 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); + for (UINT i = 0; i < s->plane_count; i++) + linesizes[i] = s->plane_layouts[i].Footprint.RowPitch; - 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], + 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, }, - }, - }; - - 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], - }, - }, - }; + }; + } 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_ResourceBarrier(s->command_list, s->plane_count, barriers); - ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list, - &staging_y_location, 0, 0, 0, - &texture_y_location, NULL); + 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_uv_location, 0, 0, 0, - &texture_uv_location, NULL); + 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_ResourceBarrier(s->command_list, s->plane_count, barriers); - ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list, - &texture_y_location, 0, 0, 0, - &staging_y_location, NULL); + 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_uv_location, 0, 0, 0, - &staging_uv_location, NULL); + 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)); -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
