mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-11-06 05:17:42 +00:00
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>
This commit is contained in:
1 parent
b034eb5e7e
commit
3eaf97e12c
1 file changed
+122
-92
+122
-92
@@ -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, s->plane_count, barriers);
|
||||
|
||||
ID3D12GraphicsCommandList_ResourceBarrier(s->command_list, 1, &barrier);
|
||||
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_y_location, 0, 0, 0,
|
||||
&texture_y_location, NULL);
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
|
||||
&staging_location, 0, 0, 0,
|
||||
&texture_location, NULL);
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(s->command_list,
|
||||
&staging_uv_location, 0, 0, 0,
|
||||
&texture_uv_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));
|
||||
|
||||
|
||||
Reference in new issue
Block a user