mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-02-04 14:30:55 +08:00
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.
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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,
|
||||
barriers[2] = TRANSITION_BARRIER(pic->encoded_metadata,
|
||||
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE);
|
||||
barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata,
|
||||
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];
|
||||
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));
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds,
|
||||
refs_barriers);
|
||||
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];
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user