mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 10:04:37 +08:00
avfilter/vf_scale_d3d12: fix command allocator sync before reset
Replace the single command allocator with a pooled allocator approach matching d3d12va_encode.c. Each allocator is tagged with the fence value that must complete before it can be reused. Fixes #24483.
This commit is contained in:
1 parent
6a030f3dd2
commit
b227d1e4be
1 file changed
+98
-35
@@ -18,6 +18,7 @@
|
||||
|
||||
#define COBJMACROS
|
||||
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "compat/w32dlfcn.h"
|
||||
@@ -30,6 +31,11 @@
|
||||
#include "scale_eval.h"
|
||||
#include "video.h"
|
||||
|
||||
typedef struct D3D12ScaleCommandAllocator {
|
||||
ID3D12CommandAllocator *command_allocator;
|
||||
UINT64 fence_value;
|
||||
} D3D12ScaleCommandAllocator;
|
||||
|
||||
typedef struct ScaleD3D12Context {
|
||||
const AVClass *classCtx;
|
||||
char *w_expr;
|
||||
@@ -42,7 +48,8 @@ typedef struct ScaleD3D12Context {
|
||||
ID3D12VideoProcessor *video_processor;
|
||||
ID3D12CommandQueue *command_queue;
|
||||
ID3D12VideoProcessCommandList *command_list;
|
||||
ID3D12CommandAllocator *command_allocator;
|
||||
|
||||
AVFifo *allocator_queue;
|
||||
|
||||
/* Synchronization */
|
||||
ID3D12Fence *fence;
|
||||
@@ -71,9 +78,49 @@ static av_cold int scale_d3d12_init(AVFilterContext *ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scale_d3d12_get_valid_command_allocator(ScaleD3D12Context *s, AVFilterContext *ctx,
|
||||
ID3D12CommandAllocator **ppAllocator)
|
||||
{
|
||||
HRESULT hr;
|
||||
D3D12ScaleCommandAllocator 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 a new command allocator: HRESULT 0x%lX\n", hr);
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scale_d3d12_discard_command_allocator(ScaleD3D12Context *s, ID3D12CommandAllocator *pAllocator,
|
||||
UINT64 fence_value)
|
||||
{
|
||||
D3D12ScaleCommandAllocator allocator = {
|
||||
.command_allocator = pAllocator,
|
||||
.fence_value = fence_value,
|
||||
};
|
||||
|
||||
av_fifo_write(s->allocator_queue, &allocator, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_d3d12_resources(ScaleD3D12Context *s) {
|
||||
UINT64 fence_value;
|
||||
HRESULT hr;
|
||||
D3D12ScaleCommandAllocator allocator;
|
||||
|
||||
/* Wait for all GPU operations to complete before releasing resources */
|
||||
if (s->command_queue && s->fence && s->fence_event) {
|
||||
fence_value = s->fence_value - 1;
|
||||
@@ -104,9 +151,10 @@ static void release_d3d12_resources(ScaleD3D12Context *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) {
|
||||
@@ -181,6 +229,8 @@ static AVRational get_input_framerate(AVFilterContext *ctx, AVFilterLink *inlink
|
||||
|
||||
static int scale_d3d12_configure_processor(ScaleD3D12Context *s, AVFilterContext *ctx) {
|
||||
HRESULT hr;
|
||||
int ret;
|
||||
ID3D12CommandAllocator *command_allocator = NULL;
|
||||
|
||||
if (s->output_format == DXGI_FORMAT_UNKNOWN) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Output format not initialized\n");
|
||||
@@ -311,35 +361,6 @@ static int scale_d3d12_configure_processor(ScaleD3D12Context *s, AVFilterContext
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
hr = ID3D12Device_CreateCommandAllocator(
|
||||
s->device,
|
||||
D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
|
||||
&IID_ID3D12CommandAllocator,
|
||||
(void **)&s->command_allocator
|
||||
);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Failed to create command allocator: HRESULT 0x%lX\n", hr);
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
hr = ID3D12Device_CreateCommandList(
|
||||
s->device,
|
||||
0,
|
||||
D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
|
||||
s->command_allocator,
|
||||
NULL,
|
||||
&IID_ID3D12VideoProcessCommandList,
|
||||
(void **)&s->command_list
|
||||
);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Failed to create command list: HRESULT 0x%lX\n", hr);
|
||||
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);
|
||||
@@ -353,6 +374,36 @@ static int scale_d3d12_configure_processor(ScaleD3D12Context *s, AVFilterContext
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
s->allocator_queue = av_fifo_alloc2(2, sizeof(D3D12ScaleCommandAllocator), AV_FIFO_FLAG_AUTO_GROW);
|
||||
if (!s->allocator_queue)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = scale_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,
|
||||
command_allocator,
|
||||
NULL,
|
||||
&IID_ID3D12VideoProcessCommandList,
|
||||
(void **)&s->command_list
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
ret = scale_d3d12_discard_command_allocator(s, command_allocator, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_log(ctx, AV_LOG_VERBOSE, "D3D12 video processor successfully configured\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -365,6 +416,7 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in)
|
||||
AVFrame *out = NULL;
|
||||
int ret = 0;
|
||||
HRESULT hr;
|
||||
ID3D12CommandAllocator *command_allocator = NULL;
|
||||
|
||||
if (!in) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Null input frame\n");
|
||||
@@ -478,14 +530,18 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in)
|
||||
}
|
||||
}
|
||||
|
||||
hr = ID3D12CommandAllocator_Reset(s->command_allocator);
|
||||
ret = scale_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;
|
||||
@@ -576,6 +632,11 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in)
|
||||
output_frame->sync_ctx.fence_value = s->fence_value;
|
||||
ID3D12Fence_AddRef(s->fence); ///< Increment reference count
|
||||
|
||||
ret = scale_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, in);
|
||||
@@ -593,6 +654,8 @@ static int scale_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *in)
|
||||
return ff_filter_frame(outlink, out);
|
||||
|
||||
fail:
|
||||
if (command_allocator)
|
||||
scale_d3d12_discard_command_allocator(s, command_allocator, s->fence_value);
|
||||
av_frame_free(&in);
|
||||
av_frame_free(&out);
|
||||
return ret;
|
||||
|
||||
Reference in new issue
Block a user