mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-03 14:32:16 +02:00
avfilter/vf_bwdif: Add a filter_line3 method for optimisation
Add an optional filter_line3 to the available optimisations. filter_line3 is equivalent to filter_line, memcpy, filter_line filter_line shares quite a number of loads and some calculations in common with its next iteration and testing shows that using aarch64 neon filter_line3s performance is 30% better than two filter_lines and a memcpy. Adds a test for vf_bwdif filter_line3 to checkasm Rounds job start lines down to a multiple of 4. This means that if filter_line3 exists then filter_line will not sometimes be called once at the end of a slice depending on thread count. The final slice may do up to 3 extra lines but filter_edge is faster than filter_line so it is unlikely to create any noticable thread load variation. Signed-off-by: John Cox <jc@kynesim.co.uk> Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
parent
94cb94a2c0
commit
697533e76d
@ -35,6 +35,9 @@ typedef struct BWDIFContext {
|
||||
void (*filter_edge)(void *dst, void *prev, void *cur, void *next,
|
||||
int w, int prefs, int mrefs, int prefs2, int mrefs2,
|
||||
int parity, int clip_max, int spat);
|
||||
void (*filter_line3)(void *dst, int dstride,
|
||||
const void *prev, const void *cur, const void *next, int prefs,
|
||||
int w, int parity, int clip_max);
|
||||
} BWDIFContext;
|
||||
|
||||
void ff_bwdif_init_filter_line(BWDIFContext *bwdif, int bit_depth);
|
||||
@ -53,4 +56,8 @@ void ff_bwdif_filter_line_c(void *dst1, void *prev1, void *cur1, void *next1,
|
||||
int prefs3, int mrefs3, int prefs4, int mrefs4,
|
||||
int parity, int clip_max);
|
||||
|
||||
void ff_bwdif_filter_line3_c(void * dst1, int d_stride,
|
||||
const void * prev1, const void * cur1, const void * next1, int s_stride,
|
||||
int w, int parity, int clip_max);
|
||||
|
||||
#endif /* AVFILTER_BWDIF_H */
|
||||
|
@ -150,6 +150,31 @@ void ff_bwdif_filter_line_c(void *dst1, void *prev1, void *cur1, void *next1,
|
||||
FILTER2()
|
||||
}
|
||||
|
||||
#define NEXT_LINE()\
|
||||
dst += d_stride; \
|
||||
prev += prefs; \
|
||||
cur += prefs; \
|
||||
next += prefs;
|
||||
|
||||
void ff_bwdif_filter_line3_c(void * dst1, int d_stride,
|
||||
const void * prev1, const void * cur1, const void * next1, int s_stride,
|
||||
int w, int parity, int clip_max)
|
||||
{
|
||||
const int prefs = s_stride;
|
||||
uint8_t * dst = dst1;
|
||||
const uint8_t * prev = prev1;
|
||||
const uint8_t * cur = cur1;
|
||||
const uint8_t * next = next1;
|
||||
|
||||
ff_bwdif_filter_line_c(dst, (void*)prev, (void*)cur, (void*)next, w,
|
||||
prefs, -prefs, prefs * 2, - prefs * 2, prefs * 3, -prefs * 3, prefs * 4, -prefs * 4, parity, clip_max);
|
||||
NEXT_LINE();
|
||||
memcpy(dst, cur, w);
|
||||
NEXT_LINE();
|
||||
ff_bwdif_filter_line_c(dst, (void*)prev, (void*)cur, (void*)next, w,
|
||||
prefs, -prefs, prefs * 2, - prefs * 2, prefs * 3, -prefs * 3, prefs * 4, -prefs * 4, parity, clip_max);
|
||||
}
|
||||
|
||||
void ff_bwdif_filter_edge_c(void *dst1, void *prev1, void *cur1, void *next1,
|
||||
int w, int prefs, int mrefs, int prefs2, int mrefs2,
|
||||
int parity, int clip_max, int spat)
|
||||
@ -212,6 +237,13 @@ static void filter_edge_16bit(void *dst1, void *prev1, void *cur1, void *next1,
|
||||
FILTER2()
|
||||
}
|
||||
|
||||
// Round job start line down to multiple of 4 so that if filter_line3 exists
|
||||
// and the frame is a multiple of 4 high then filter_line will never be called
|
||||
static inline int job_start(const int jobnr, const int nb_jobs, const int h)
|
||||
{
|
||||
return jobnr >= nb_jobs ? h : ((h * jobnr) / nb_jobs) & ~3;
|
||||
}
|
||||
|
||||
static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
|
||||
{
|
||||
BWDIFContext *s = ctx->priv;
|
||||
@ -221,8 +253,8 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
|
||||
int clip_max = (1 << (yadif->csp->comp[td->plane].depth)) - 1;
|
||||
int df = (yadif->csp->comp[td->plane].depth + 7) / 8;
|
||||
int refs = linesize / df;
|
||||
int slice_start = (td->h * jobnr ) / nb_jobs;
|
||||
int slice_end = (td->h * (jobnr+1)) / nb_jobs;
|
||||
int slice_start = job_start(jobnr, nb_jobs, td->h);
|
||||
int slice_end = job_start(jobnr + 1, nb_jobs, td->h);
|
||||
int y;
|
||||
|
||||
for (y = slice_start; y < slice_end; y++) {
|
||||
@ -244,6 +276,11 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
|
||||
refs << 1, -(refs << 1),
|
||||
td->parity ^ td->tff, clip_max,
|
||||
(y < 2) || ((y + 3) > td->h) ? 0 : 1);
|
||||
} else if (s->filter_line3 && y + 2 < slice_end && y + 6 < td->h) {
|
||||
s->filter_line3(dst, td->frame->linesize[td->plane],
|
||||
prev, cur, next, linesize, td->w,
|
||||
td->parity ^ td->tff, clip_max);
|
||||
y += 2;
|
||||
} else {
|
||||
s->filter_line(dst, prev, cur, next, td->w,
|
||||
refs, -refs, refs << 1, -(refs << 1),
|
||||
@ -280,7 +317,7 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic,
|
||||
td.plane = i;
|
||||
|
||||
ff_filter_execute(ctx, filter_slice, &td, NULL,
|
||||
FFMIN(h, ff_filter_get_nb_threads(ctx)));
|
||||
FFMIN((h+3)/4, ff_filter_get_nb_threads(ctx)));
|
||||
}
|
||||
if (yadif->current_field == YADIF_FIELD_END) {
|
||||
yadif->current_field = YADIF_FIELD_NORMAL;
|
||||
@ -357,6 +394,7 @@ static int config_props(AVFilterLink *link)
|
||||
|
||||
av_cold void ff_bwdif_init_filter_line(BWDIFContext *s, int bit_depth)
|
||||
{
|
||||
s->filter_line3 = 0;
|
||||
if (bit_depth > 8) {
|
||||
s->filter_intra = filter_intra_16bit;
|
||||
s->filter_line = filter_line_c_16bit;
|
||||
|
@ -28,6 +28,10 @@
|
||||
for (size_t i = 0; i < count; i++) \
|
||||
buf0[i] = buf1[i] = rnd() & mask
|
||||
|
||||
#define randomize_overflow_check(buf0, buf1, mask, count) \
|
||||
for (size_t i = 0; i < count; i++) \
|
||||
buf0[i] = buf1[i] = (rnd() & 1) != 0 ? mask : 0;
|
||||
|
||||
#define BODY(type, depth) \
|
||||
do { \
|
||||
type prev0[9*WIDTH], prev1[9*WIDTH]; \
|
||||
@ -83,6 +87,83 @@ void checkasm_check_vf_bwdif(void)
|
||||
report("bwdif10");
|
||||
}
|
||||
|
||||
if (!ctx_8.filter_line3)
|
||||
ctx_8.filter_line3 = ff_bwdif_filter_line3_c;
|
||||
|
||||
{
|
||||
LOCAL_ALIGNED_16(uint8_t, prev0, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, prev1, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, next0, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, next1, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, cur0, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, cur1, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, dst0, [WIDTH*3]);
|
||||
LOCAL_ALIGNED_16(uint8_t, dst1, [WIDTH*3]);
|
||||
const int stride = WIDTH;
|
||||
const int mask = (1<<8)-1;
|
||||
int parity;
|
||||
|
||||
for (parity = 0; parity != 2; ++parity) {
|
||||
if (check_func(ctx_8.filter_line3, "bwdif8.line3.rnd.p%d", parity)) {
|
||||
|
||||
declare_func(void, void * dst1, int d_stride,
|
||||
const void * prev1, const void * cur1, const void * next1, int prefs,
|
||||
int w, int parity, int clip_max);
|
||||
|
||||
randomize_buffers(prev0, prev1, mask, 11*WIDTH);
|
||||
randomize_buffers(next0, next1, mask, 11*WIDTH);
|
||||
randomize_buffers( cur0, cur1, mask, 11*WIDTH);
|
||||
|
||||
call_ref(dst0, stride,
|
||||
prev0 + stride * 4, cur0 + stride * 4, next0 + stride * 4, stride,
|
||||
WIDTH, parity, mask);
|
||||
call_new(dst1, stride,
|
||||
prev1 + stride * 4, cur1 + stride * 4, next1 + stride * 4, stride,
|
||||
WIDTH, parity, mask);
|
||||
|
||||
if (memcmp(dst0, dst1, WIDTH*3)
|
||||
|| memcmp(prev0, prev1, WIDTH*11)
|
||||
|| memcmp(next0, next1, WIDTH*11)
|
||||
|| memcmp( cur0, cur1, WIDTH*11))
|
||||
fail();
|
||||
|
||||
bench_new(dst1, stride,
|
||||
prev1 + stride * 4, cur1 + stride * 4, next1 + stride * 4, stride,
|
||||
WIDTH, parity, mask);
|
||||
}
|
||||
}
|
||||
|
||||
// Use just 0s and ~0s to try to provoke bad cropping or overflow
|
||||
// Parity makes no difference to this test so just test 0
|
||||
if (check_func(ctx_8.filter_line3, "bwdif8.line3.overflow")) {
|
||||
|
||||
declare_func(void, void * dst1, int d_stride,
|
||||
const void * prev1, const void * cur1, const void * next1, int prefs,
|
||||
int w, int parity, int clip_max);
|
||||
|
||||
randomize_overflow_check(prev0, prev1, mask, 11*WIDTH);
|
||||
randomize_overflow_check(next0, next1, mask, 11*WIDTH);
|
||||
randomize_overflow_check( cur0, cur1, mask, 11*WIDTH);
|
||||
|
||||
call_ref(dst0, stride,
|
||||
prev0 + stride * 4, cur0 + stride * 4, next0 + stride * 4, stride,
|
||||
WIDTH, 0, mask);
|
||||
call_new(dst1, stride,
|
||||
prev1 + stride * 4, cur1 + stride * 4, next1 + stride * 4, stride,
|
||||
WIDTH, 0, mask);
|
||||
|
||||
if (memcmp(dst0, dst1, WIDTH*3)
|
||||
|| memcmp(prev0, prev1, WIDTH*11)
|
||||
|| memcmp(next0, next1, WIDTH*11)
|
||||
|| memcmp( cur0, cur1, WIDTH*11))
|
||||
fail();
|
||||
|
||||
// No point to benching
|
||||
}
|
||||
|
||||
report("bwdif8.line3");
|
||||
}
|
||||
|
||||
{
|
||||
LOCAL_ALIGNED_16(uint8_t, prev0, [11*WIDTH]);
|
||||
LOCAL_ALIGNED_16(uint8_t, prev1, [11*WIDTH]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user