This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new 7bc3576910 avfilter/vf_deinterlace_d3d12: fix command allocator sync
before reset
7bc3576910 is described below
commit 7bc357691081c23963c014d08f43d381c977208c
Author: Dong Nguyen <[email protected]>
AuthorDate: Mon Oct 5 15:35:14 2026 -0400
Commit: Steven Xiao <[email protected]>
CommitDate: Fri Oct 9 15:18:32 2026 +0000
avfilter/vf_deinterlace_d3d12: fix command allocator sync before reset
The fix replaces the single allocator with a pool of allocators tagged with
fence values, matching the pattern in d3d12va_encode.c. Each allocator is only
reused after its fence value has been reached.
This is a follow up action for issue report
https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/24483. The current
vf_deinterlace_d3d12 has similar issue: ID3D12CommandAllocator_Reset() was
called each frame without checking that the GPU had finished using that
allocator. If the GPU was still processing the previous frame's commands,
resetting the allocator could corrupt or discard in flight work, leading to
rendering errors or GPU faults.
---
libavfilter/vf_deinterlace_d3d12.c | 119 ++++++++++++++++++++++++++++---------
1 file changed, 90 insertions(+), 29 deletions(-)
diff --git a/libavfilter/vf_deinterlace_d3d12.c
b/libavfilter/vf_deinterlace_d3d12.c
index 5eb9b227f1..ab0d47f27a 100644
--- a/libavfilter/vf_deinterlace_d3d12.c
+++ b/libavfilter/vf_deinterlace_d3d12.c
@@ -22,6 +22,7 @@
#define COBJMACROS
+#include "libavutil/fifo.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
@@ -43,6 +44,11 @@ enum DeinterlaceD3D12Method {
DEINT_D3D12_METHOD_CUSTOM = 2, // Driver-defined advanced
deinterlacing
};
+typedef struct CommandAllocator {
+ ID3D12CommandAllocator *command_allocator;
+ UINT64 fence_value;
+} CommandAllocator;
+
typedef struct DeinterlaceD3D12Context {
const AVClass *classCtx;
@@ -57,7 +63,8 @@ typedef struct DeinterlaceD3D12Context {
ID3D12VideoProcessor *video_processor;
ID3D12CommandQueue *command_queue;
ID3D12VideoProcessCommandList *command_list;
- ID3D12CommandAllocator *command_allocator;
+
+ AVFifo *allocator_queue;
/* Synchronization */
ID3D12Fence *fence;
@@ -101,15 +108,53 @@ typedef struct DeinterlaceD3D12Context {
static av_cold int deint_d3d12_init(AVFilterContext *ctx)
{
DeinterlaceD3D12Context *s = ctx->priv;
- s->fence_value = 1;
s->processor_configured = 0;
return 0;
}
+static int deint_d3d12_get_valid_command_allocator(DeinterlaceD3D12Context *s,
AVFilterContext *ctx,
+ ID3D12CommandAllocator
**ppAllocator)
+{
+ HRESULT hr;
+ CommandAllocator allocator;
+
+ if (av_fifo_peek(s->allocator_queue, &allocator, 1, 0) >= 0) {
+ UINT64 completed = ID3D12Fence_GetCompletedValue(s->fence);
+ if (completed >= allocator.fence_value) {
+ *ppAllocator = allocator.command_allocator;
+ av_fifo_read(s->allocator_queue, &allocator, 1);
+ return 0;
+ }
+ }
+
+ hr = ID3D12Device_CreateCommandAllocator(s->device,
D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
+ &IID_ID3D12CommandAllocator,
(void **)ppAllocator);
+ if (FAILED(hr)) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to create command allocator: HRESULT
0x%lX\n", hr);
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+static int deint_d3d12_discard_command_allocator(DeinterlaceD3D12Context *s,
ID3D12CommandAllocator *pAllocator,
+ UINT64 fence_value)
+{
+ CommandAllocator allocator = {
+ .command_allocator = pAllocator,
+ .fence_value = fence_value,
+ };
+
+ av_fifo_write(s->allocator_queue, &allocator, 1);
+
+ return 0;
+}
+
static void release_d3d12_resources(DeinterlaceD3D12Context *s)
{
UINT64 fence_value;
HRESULT hr;
+ CommandAllocator allocator;
/* Wait for all GPU operations to complete before releasing resources */
if (s->command_queue && s->fence && s->fence_event) {
@@ -141,9 +186,10 @@ static void
release_d3d12_resources(DeinterlaceD3D12Context *s)
s->command_list = NULL;
}
- if (s->command_allocator) {
- ID3D12CommandAllocator_Release(s->command_allocator);
- s->command_allocator = NULL;
+ if (s->allocator_queue) {
+ while (av_fifo_read(s->allocator_queue, &allocator, 1) >= 0)
+ ID3D12CommandAllocator_Release(allocator.command_allocator);
+ av_fifo_freep2(&s->allocator_queue);
}
if (s->video_processor) {
@@ -263,10 +309,12 @@ static int
deint_d3d12_configure_processor(DeinterlaceD3D12Context *s,
AVFrame *in)
{
HRESULT hr;
+ int ret;
AVHWDeviceContext *hwctx = (AVHWDeviceContext *)s->hw_device_ctx->data;
AVD3D12VADeviceContext *d3d12_hwctx = (AVD3D12VADeviceContext
*)hwctx->hwctx;
D3D12_VIDEO_PROCESS_DEINTERLACE_FLAGS deint_method;
D3D12_VIDEO_FIELD_TYPE field_type;
+ ID3D12CommandAllocator *command_allocator = NULL;
s->device = d3d12_hwctx->device;
@@ -458,23 +506,33 @@ static int
deint_d3d12_configure_processor(DeinterlaceD3D12Context *s,
return AVERROR_EXTERNAL;
}
- hr = ID3D12Device_CreateCommandAllocator(
- s->device,
- D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
- &IID_ID3D12CommandAllocator,
- (void **)&s->command_allocator
- );
-
+ hr = ID3D12Device_CreateFence(s->device, 0, D3D12_FENCE_FLAG_NONE,
&IID_ID3D12Fence, (void **)&s->fence);
if (FAILED(hr)) {
- av_log(ctx, AV_LOG_ERROR, "Failed to create command allocator: HRESULT
0x%lX\n", hr);
+ av_log(ctx, AV_LOG_ERROR, "Failed to create fence: HRESULT 0x%lX\n",
hr);
return AVERROR_EXTERNAL;
}
+ s->fence_value = 1;
+
+ s->fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!s->fence_event) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to create fence event\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ s->allocator_queue = av_fifo_alloc2(2, sizeof(CommandAllocator),
AV_FIFO_FLAG_AUTO_GROW);
+ if (!s->allocator_queue)
+ return AVERROR(ENOMEM);
+
+ ret = deint_d3d12_get_valid_command_allocator(s, ctx, &command_allocator);
+ if (ret < 0)
+ return ret;
+
hr = ID3D12Device_CreateCommandList(
s->device,
0,
D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
- s->command_allocator,
+ command_allocator,
NULL,
&IID_ID3D12VideoProcessCommandList,
(void **)&s->command_list
@@ -482,24 +540,15 @@ static int
deint_d3d12_configure_processor(DeinterlaceD3D12Context *s,
if (FAILED(hr)) {
av_log(ctx, AV_LOG_ERROR, "Failed to create command list: HRESULT
0x%lX\n", hr);
+ ID3D12CommandAllocator_Release(command_allocator);
return AVERROR_EXTERNAL;
}
ID3D12VideoProcessCommandList_Close(s->command_list);
- hr = ID3D12Device_CreateFence(s->device, 0, D3D12_FENCE_FLAG_NONE,
&IID_ID3D12Fence, (void **)&s->fence);
- if (FAILED(hr)) {
- av_log(ctx, AV_LOG_ERROR, "Failed to create fence: HRESULT 0x%lX\n",
hr);
- return AVERROR_EXTERNAL;
- }
-
- s->fence_value = 1;
-
- s->fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!s->fence_event) {
- av_log(ctx, AV_LOG_ERROR, "Failed to create fence event\n");
- return AVERROR_EXTERNAL;
- }
+ ret = deint_d3d12_discard_command_allocator(s, command_allocator, 0);
+ if (ret < 0)
+ return ret;
s->processor_configured = 1;
av_log(ctx, AV_LOG_VERBOSE, "D3D12 deinterlace processor successfully
configured\n");
@@ -534,6 +583,7 @@ static int deint_d3d12_process_frame(AVFilterContext *ctx,
int ret = 0;
int i;
HRESULT hr;
+ ID3D12CommandAllocator *command_allocator = NULL;
AVD3D12VAFrame *in_d3d12_frame = (AVD3D12VAFrame *)input_frame->data[0];
@@ -638,14 +688,18 @@ static int deint_d3d12_process_frame(AVFilterContext *ctx,
}
}
- hr = ID3D12CommandAllocator_Reset(s->command_allocator);
+ ret = deint_d3d12_get_valid_command_allocator(s, ctx, &command_allocator);
+ if (ret < 0)
+ goto fail;
+
+ hr = ID3D12CommandAllocator_Reset(command_allocator);
if (FAILED(hr)) {
av_log(ctx, AV_LOG_ERROR, "Failed to reset command allocator: HRESULT
0x%lX\n", hr);
ret = AVERROR_EXTERNAL;
goto fail;
}
- hr = ID3D12VideoProcessCommandList_Reset(s->command_list,
s->command_allocator);
+ hr = ID3D12VideoProcessCommandList_Reset(s->command_list,
command_allocator);
if (FAILED(hr)) {
av_log(ctx, AV_LOG_ERROR, "Failed to reset command list: HRESULT
0x%lX\n", hr);
ret = AVERROR_EXTERNAL;
@@ -742,6 +796,11 @@ static int deint_d3d12_process_frame(AVFilterContext *ctx,
out_d3d12_frame->sync_ctx.fence_value = s->fence_value;
ID3D12Fence_AddRef(s->fence);
+ ret = deint_d3d12_discard_command_allocator(s, command_allocator,
s->fence_value);
+ command_allocator = NULL;
+ if (ret < 0)
+ goto fail;
+
s->fence_value++;
ret = av_frame_copy_props(out, input_frame);
@@ -775,6 +834,8 @@ static int deint_d3d12_process_frame(AVFilterContext *ctx,
return ff_filter_frame(outlink, out);
fail:
+ if (command_allocator)
+ deint_d3d12_discard_command_allocator(s, command_allocator,
s->fence_value);
av_frame_free(&out);
return ret;
}
--
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]