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]

Reply via email to