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]