swscale: move yuv2yuvX_sse3 to yasm, unrolls main loop
And other small optimizations for ~20% speedup.
This commit is contained in:
parent
1628409b18
commit
554c2bc708
@ -13,3 +13,4 @@ X86ASM-OBJS += x86/input.o \
|
|||||||
x86/scale.o \
|
x86/scale.o \
|
||||||
x86/rgb_2_rgb.o \
|
x86/rgb_2_rgb.o \
|
||||||
x86/yuv_2_rgb.o \
|
x86/yuv_2_rgb.o \
|
||||||
|
x86/yuv2yuvX.o \
|
||||||
|
@ -63,6 +63,16 @@ DECLARE_ASM_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL;
|
|||||||
DECLARE_ASM_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL;
|
DECLARE_ASM_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL;
|
||||||
|
|
||||||
|
|
||||||
|
#define YUV2YUVX_FUNC_DECL(opt) \
|
||||||
|
static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, const int16_t **src, \
|
||||||
|
uint8_t *dest, int dstW, \
|
||||||
|
const uint8_t *dither, int offset); \
|
||||||
|
|
||||||
|
YUV2YUVX_FUNC_DECL(mmx)
|
||||||
|
YUV2YUVX_FUNC_DECL(mmxext)
|
||||||
|
YUV2YUVX_FUNC_DECL(sse3)
|
||||||
|
YUV2YUVX_FUNC_DECL(avx2)
|
||||||
|
|
||||||
//MMX versions
|
//MMX versions
|
||||||
#if HAVE_MMX_INLINE
|
#if HAVE_MMX_INLINE
|
||||||
#undef RENAME
|
#undef RENAME
|
||||||
@ -198,81 +208,44 @@ void ff_updateMMXDitherTables(SwsContext *c, int dstY)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_MMXEXT
|
#if HAVE_MMXEXT
|
||||||
static void yuv2yuvX_sse3(const int16_t *filter, int filterSize,
|
#define YUV2YUVX_FUNC_MMX(opt, step) \
|
||||||
const int16_t **src, uint8_t *dest, int dstW,
|
void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
|
||||||
const uint8_t *dither, int offset)
|
uint8_t *dest, int dstW, \
|
||||||
{
|
const uint8_t *dither, int offset); \
|
||||||
if(((uintptr_t)dest) & 15){
|
static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, \
|
||||||
yuv2yuvX_mmxext(filter, filterSize, src, dest, dstW, dither, offset);
|
const int16_t **src, uint8_t *dest, int dstW, \
|
||||||
return;
|
const uint8_t *dither, int offset) \
|
||||||
|
{ \
|
||||||
|
ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, dstW + offset, dither, offset); \
|
||||||
|
return; \
|
||||||
}
|
}
|
||||||
filterSize--;
|
|
||||||
#define MAIN_FUNCTION \
|
|
||||||
"pxor %%xmm0, %%xmm0 \n\t" \
|
|
||||||
"punpcklbw %%xmm0, %%xmm3 \n\t" \
|
|
||||||
"movd %4, %%xmm1 \n\t" \
|
|
||||||
"punpcklwd %%xmm1, %%xmm1 \n\t" \
|
|
||||||
"punpckldq %%xmm1, %%xmm1 \n\t" \
|
|
||||||
"punpcklqdq %%xmm1, %%xmm1 \n\t" \
|
|
||||||
"psllw $3, %%xmm1 \n\t" \
|
|
||||||
"paddw %%xmm1, %%xmm3 \n\t" \
|
|
||||||
"psraw $4, %%xmm3 \n\t" \
|
|
||||||
"movdqa %%xmm3, %%xmm4 \n\t" \
|
|
||||||
"movdqa %%xmm3, %%xmm7 \n\t" \
|
|
||||||
"movl %3, %%ecx \n\t" \
|
|
||||||
"mov %0, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
".p2align 4 \n\t" /* FIXME Unroll? */\
|
|
||||||
"1: \n\t"\
|
|
||||||
"movddup 8(%%"FF_REG_d"), %%xmm0 \n\t" /* filterCoeff */\
|
|
||||||
"movdqa (%%"FF_REG_S", %%"FF_REG_c", 2), %%xmm2 \n\t" /* srcData */\
|
|
||||||
"movdqa 16(%%"FF_REG_S", %%"FF_REG_c", 2), %%xmm5 \n\t" /* srcData */\
|
|
||||||
"add $16, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
"test %%"FF_REG_S", %%"FF_REG_S" \n\t"\
|
|
||||||
"pmulhw %%xmm0, %%xmm2 \n\t"\
|
|
||||||
"pmulhw %%xmm0, %%xmm5 \n\t"\
|
|
||||||
"paddw %%xmm2, %%xmm3 \n\t"\
|
|
||||||
"paddw %%xmm5, %%xmm4 \n\t"\
|
|
||||||
" jnz 1b \n\t"\
|
|
||||||
"psraw $3, %%xmm3 \n\t"\
|
|
||||||
"psraw $3, %%xmm4 \n\t"\
|
|
||||||
"packuswb %%xmm4, %%xmm3 \n\t"\
|
|
||||||
"movntdq %%xmm3, (%1, %%"FF_REG_c") \n\t"\
|
|
||||||
"add $16, %%"FF_REG_c" \n\t"\
|
|
||||||
"cmp %2, %%"FF_REG_c" \n\t"\
|
|
||||||
"movdqa %%xmm7, %%xmm3 \n\t" \
|
|
||||||
"movdqa %%xmm7, %%xmm4 \n\t" \
|
|
||||||
"mov %0, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
"jb 1b \n\t"
|
|
||||||
|
|
||||||
if (offset) {
|
#define YUV2YUVX_FUNC(opt, step) \
|
||||||
__asm__ volatile(
|
void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
|
||||||
"movq %5, %%xmm3 \n\t"
|
uint8_t *dest, int dstW, \
|
||||||
"movdqa %%xmm3, %%xmm4 \n\t"
|
const uint8_t *dither, int offset); \
|
||||||
"psrlq $24, %%xmm3 \n\t"
|
static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, \
|
||||||
"psllq $40, %%xmm4 \n\t"
|
const int16_t **src, uint8_t *dest, int dstW, \
|
||||||
"por %%xmm4, %%xmm3 \n\t"
|
const uint8_t *dither, int offset) \
|
||||||
MAIN_FUNCTION
|
{ \
|
||||||
:: "g" (filter),
|
int remainder = (dstW % step); \
|
||||||
"r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset),
|
int pixelsProcessed = dstW - remainder; \
|
||||||
"m"(filterSize), "m"(((uint64_t *) dither)[0])
|
if(((uintptr_t)dest) & 15){ \
|
||||||
: XMM_CLOBBERS("%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" , "%xmm4" , "%xmm5" , "%xmm7" ,)
|
yuv2yuvX_mmx(filter, filterSize, src, dest, dstW, dither, offset); \
|
||||||
"%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_c
|
return; \
|
||||||
);
|
} \
|
||||||
} else {
|
ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, pixelsProcessed + offset, dither, offset); \
|
||||||
__asm__ volatile(
|
if(remainder > 0){ \
|
||||||
"movq %5, %%xmm3 \n\t"
|
ff_yuv2yuvX_mmx(filter, filterSize - 1, pixelsProcessed, dest - offset, pixelsProcessed + remainder + offset, dither, offset); \
|
||||||
MAIN_FUNCTION
|
} \
|
||||||
:: "g" (filter),
|
return; \
|
||||||
"r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset),
|
|
||||||
"m"(filterSize), "m"(((uint64_t *) dither)[0])
|
|
||||||
: XMM_CLOBBERS("%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" , "%xmm4" , "%xmm5" , "%xmm7" ,)
|
|
||||||
"%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_c
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YUV2YUVX_FUNC_MMX(mmx, 16)
|
||||||
|
YUV2YUVX_FUNC_MMX(mmxext, 16)
|
||||||
|
YUV2YUVX_FUNC(sse3, 32)
|
||||||
|
YUV2YUVX_FUNC(avx2, 64)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* HAVE_INLINE_ASM */
|
#endif /* HAVE_INLINE_ASM */
|
||||||
@ -403,10 +376,15 @@ av_cold void ff_sws_init_swscale_x86(SwsContext *c)
|
|||||||
#if HAVE_MMXEXT_INLINE
|
#if HAVE_MMXEXT_INLINE
|
||||||
if (INLINE_MMXEXT(cpu_flags))
|
if (INLINE_MMXEXT(cpu_flags))
|
||||||
sws_init_swscale_mmxext(c);
|
sws_init_swscale_mmxext(c);
|
||||||
if (cpu_flags & AV_CPU_FLAG_SSE3){
|
if (cpu_flags & AV_CPU_FLAG_AVX2){
|
||||||
if(c->use_mmx_vfilter && !(c->flags & SWS_ACCURATE_RND))
|
if(c->use_mmx_vfilter && !(c->flags & SWS_ACCURATE_RND)){
|
||||||
|
c->yuv2planeX = yuv2yuvX_avx2;
|
||||||
|
}
|
||||||
|
} else if (cpu_flags & AV_CPU_FLAG_SSE3){
|
||||||
|
if(c->use_mmx_vfilter && !(c->flags & SWS_ACCURATE_RND)){
|
||||||
c->yuv2planeX = yuv2yuvX_sse3;
|
c->yuv2planeX = yuv2yuvX_sse3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt1, opt2) do { \
|
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt1, opt2) do { \
|
||||||
|
@ -38,88 +38,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#define MOVNTQ(a,b) REAL_MOVNTQ(a,b)
|
#define MOVNTQ(a,b) REAL_MOVNTQ(a,b)
|
||||||
|
|
||||||
#if !COMPILE_TEMPLATE_MMXEXT
|
|
||||||
static av_always_inline void
|
|
||||||
dither_8to16(const uint8_t *srcDither, int rot)
|
|
||||||
{
|
|
||||||
if (rot) {
|
|
||||||
__asm__ volatile("pxor %%mm0, %%mm0\n\t"
|
|
||||||
"movq (%0), %%mm3\n\t"
|
|
||||||
"movq %%mm3, %%mm4\n\t"
|
|
||||||
"psrlq $24, %%mm3\n\t"
|
|
||||||
"psllq $40, %%mm4\n\t"
|
|
||||||
"por %%mm4, %%mm3\n\t"
|
|
||||||
"movq %%mm3, %%mm4\n\t"
|
|
||||||
"punpcklbw %%mm0, %%mm3\n\t"
|
|
||||||
"punpckhbw %%mm0, %%mm4\n\t"
|
|
||||||
:: "r"(srcDither)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
__asm__ volatile("pxor %%mm0, %%mm0\n\t"
|
|
||||||
"movq (%0), %%mm3\n\t"
|
|
||||||
"movq %%mm3, %%mm4\n\t"
|
|
||||||
"punpcklbw %%mm0, %%mm3\n\t"
|
|
||||||
"punpckhbw %%mm0, %%mm4\n\t"
|
|
||||||
:: "r"(srcDither)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void RENAME(yuv2yuvX)(const int16_t *filter, int filterSize,
|
|
||||||
const int16_t **src, uint8_t *dest, int dstW,
|
|
||||||
const uint8_t *dither, int offset)
|
|
||||||
{
|
|
||||||
dither_8to16(dither, offset);
|
|
||||||
filterSize--;
|
|
||||||
__asm__ volatile(
|
|
||||||
"movd %0, %%mm1\n\t"
|
|
||||||
"punpcklwd %%mm1, %%mm1\n\t"
|
|
||||||
"punpckldq %%mm1, %%mm1\n\t"
|
|
||||||
"psllw $3, %%mm1\n\t"
|
|
||||||
"paddw %%mm1, %%mm3\n\t"
|
|
||||||
"paddw %%mm1, %%mm4\n\t"
|
|
||||||
"psraw $4, %%mm3\n\t"
|
|
||||||
"psraw $4, %%mm4\n\t"
|
|
||||||
::"m"(filterSize)
|
|
||||||
);
|
|
||||||
|
|
||||||
__asm__ volatile(\
|
|
||||||
"movq %%mm3, %%mm6\n\t"
|
|
||||||
"movq %%mm4, %%mm7\n\t"
|
|
||||||
"movl %3, %%ecx\n\t"
|
|
||||||
"mov %0, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
".p2align 4 \n\t" /* FIXME Unroll? */\
|
|
||||||
"1: \n\t"\
|
|
||||||
"movq 8(%%"FF_REG_d"), %%mm0 \n\t" /* filterCoeff */\
|
|
||||||
"movq (%%"FF_REG_S", %%"FF_REG_c", 2), %%mm2 \n\t" /* srcData */\
|
|
||||||
"movq 8(%%"FF_REG_S", %%"FF_REG_c", 2), %%mm5 \n\t" /* srcData */\
|
|
||||||
"add $16, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
"test %%"FF_REG_S", %%"FF_REG_S" \n\t"\
|
|
||||||
"pmulhw %%mm0, %%mm2 \n\t"\
|
|
||||||
"pmulhw %%mm0, %%mm5 \n\t"\
|
|
||||||
"paddw %%mm2, %%mm3 \n\t"\
|
|
||||||
"paddw %%mm5, %%mm4 \n\t"\
|
|
||||||
" jnz 1b \n\t"\
|
|
||||||
"psraw $3, %%mm3 \n\t"\
|
|
||||||
"psraw $3, %%mm4 \n\t"\
|
|
||||||
"packuswb %%mm4, %%mm3 \n\t"
|
|
||||||
MOVNTQ2 " %%mm3, (%1, %%"FF_REG_c")\n\t"
|
|
||||||
"add $8, %%"FF_REG_c" \n\t"\
|
|
||||||
"cmp %2, %%"FF_REG_c" \n\t"\
|
|
||||||
"movq %%mm6, %%mm3\n\t"
|
|
||||||
"movq %%mm7, %%mm4\n\t"
|
|
||||||
"mov %0, %%"FF_REG_d" \n\t"\
|
|
||||||
"mov (%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
|
|
||||||
"jb 1b \n\t"\
|
|
||||||
:: "g" (filter),
|
|
||||||
"r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset)
|
|
||||||
: "%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_c
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define YSCALEYUV2PACKEDX_UV \
|
#define YSCALEYUV2PACKEDX_UV \
|
||||||
__asm__ volatile(\
|
__asm__ volatile(\
|
||||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t"\
|
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t"\
|
||||||
|
136
libswscale/x86/yuv2yuvX.asm
Normal file
136
libswscale/x86/yuv2yuvX.asm
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
;******************************************************************************
|
||||||
|
;* x86-optimized yuv2yuvX
|
||||||
|
;* Copyright 2020 Google LLC
|
||||||
|
;* Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
|
||||||
|
;*
|
||||||
|
;* This file is part of FFmpeg.
|
||||||
|
;*
|
||||||
|
;* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
;* modify it under the terms of the GNU Lesser General Public
|
||||||
|
;* License as published by the Free Software Foundation; either
|
||||||
|
;* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
;*
|
||||||
|
;* FFmpeg is distributed in the hope that it will be useful,
|
||||||
|
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
;* Lesser General Public License for more details.
|
||||||
|
;*
|
||||||
|
;* You should have received a copy of the GNU Lesser General Public
|
||||||
|
;* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
;******************************************************************************
|
||||||
|
|
||||||
|
%include "libavutil/x86/x86util.asm"
|
||||||
|
|
||||||
|
SECTION .text
|
||||||
|
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
; yuv2yuvX
|
||||||
|
;
|
||||||
|
; void ff_yuv2yuvX_<opt>(const int16_t *filter, int filterSize,
|
||||||
|
; int srcOffset, uint8_t *dest, int dstW,
|
||||||
|
; const uint8_t *dither, int offset);
|
||||||
|
;
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%macro YUV2YUVX_FUNC 0
|
||||||
|
cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, dstW, dither, offset
|
||||||
|
%if notcpuflag(sse3)
|
||||||
|
%define movr mova
|
||||||
|
%else
|
||||||
|
%define movr movdqu
|
||||||
|
%endif
|
||||||
|
%if ARCH_X86_64
|
||||||
|
movsxd dstWq, dstWd
|
||||||
|
movsxd offsetq, offsetd
|
||||||
|
movsxd srcq, srcd
|
||||||
|
%endif ; x86-64
|
||||||
|
%if cpuflag(avx2)
|
||||||
|
vpbroadcastq m3, [ditherq]
|
||||||
|
%elif cpuflag(sse3)
|
||||||
|
movq xmm3, [ditherq]
|
||||||
|
%else
|
||||||
|
mova m3, [ditherq]
|
||||||
|
%endif ; avx2
|
||||||
|
cmp offsetd, 0
|
||||||
|
jz .offset
|
||||||
|
|
||||||
|
; offset != 0 path.
|
||||||
|
psrlq m5, m3, $18
|
||||||
|
psllq m3, m3, $28
|
||||||
|
por m3, m3, m5
|
||||||
|
|
||||||
|
.offset:
|
||||||
|
add offsetq, srcq
|
||||||
|
%if cpuflag(avx2)
|
||||||
|
movd xmm1, filterSized
|
||||||
|
vpbroadcastw m1, xmm1
|
||||||
|
%elif cpuflag(sse3)
|
||||||
|
movd xmm1, filterSized
|
||||||
|
pshuflw m1, m1, q0000
|
||||||
|
punpcklqdq m1, m1
|
||||||
|
%else
|
||||||
|
movd m1, filterSized
|
||||||
|
punpcklwd m1, m1
|
||||||
|
punpckldq m1, m1
|
||||||
|
%endif ; avx2
|
||||||
|
pxor m0, m0, m0
|
||||||
|
mov filterSizeq, filterq
|
||||||
|
mov srcq, [filterSizeq]
|
||||||
|
punpcklbw m3, m0
|
||||||
|
psllw m1, m1, 3
|
||||||
|
paddw m3, m3, m1
|
||||||
|
psraw m7, m3, 4
|
||||||
|
.outerloop:
|
||||||
|
mova m4, m7
|
||||||
|
mova m3, m7
|
||||||
|
mova m6, m7
|
||||||
|
mova m1, m7
|
||||||
|
.loop:
|
||||||
|
%if cpuflag(avx2)
|
||||||
|
vpbroadcastq m0, [filterSizeq + 8]
|
||||||
|
%elif cpuflag(sse3)
|
||||||
|
movddup m0, [filterSizeq + 8]
|
||||||
|
%else
|
||||||
|
mova m0, [filterSizeq + 8]
|
||||||
|
%endif
|
||||||
|
pmulhw m2, m0, [srcq + offsetq * 2]
|
||||||
|
pmulhw m5, m0, [srcq + offsetq * 2 + mmsize]
|
||||||
|
paddw m3, m3, m2
|
||||||
|
paddw m4, m4, m5
|
||||||
|
pmulhw m2, m0, [srcq + offsetq * 2 + 2 * mmsize]
|
||||||
|
pmulhw m5, m0, [srcq + offsetq * 2 + 3 * mmsize]
|
||||||
|
paddw m6, m6, m2
|
||||||
|
paddw m1, m1, m5
|
||||||
|
add filterSizeq, $10
|
||||||
|
mov srcq, [filterSizeq]
|
||||||
|
test srcq, srcq
|
||||||
|
jnz .loop
|
||||||
|
psraw m3, m3, 3
|
||||||
|
psraw m4, m4, 3
|
||||||
|
psraw m6, m6, 3
|
||||||
|
psraw m1, m1, 3
|
||||||
|
packuswb m3, m3, m4
|
||||||
|
packuswb m6, m6, m1
|
||||||
|
mov srcq, [filterq]
|
||||||
|
%if cpuflag(avx2)
|
||||||
|
vpermq m3, m3, 216
|
||||||
|
vpermq m6, m6, 216
|
||||||
|
%endif
|
||||||
|
movr [destq + offsetq], m3
|
||||||
|
movr [destq + offsetq + mmsize], m6
|
||||||
|
add offsetq, mmsize * 2
|
||||||
|
mov filterSizeq, filterq
|
||||||
|
cmp offsetq, dstWq
|
||||||
|
jb .outerloop
|
||||||
|
REP_RET
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
INIT_MMX mmx
|
||||||
|
YUV2YUVX_FUNC
|
||||||
|
INIT_MMX mmxext
|
||||||
|
YUV2YUVX_FUNC
|
||||||
|
INIT_XMM sse3
|
||||||
|
YUV2YUVX_FUNC
|
||||||
|
INIT_YMM avx2
|
||||||
|
YUV2YUVX_FUNC
|
@ -36,6 +36,107 @@
|
|||||||
AV_WN32(buf + j, rnd()); \
|
AV_WN32(buf + j, rnd()); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
// This reference function is the same approximate algorithm employed by the
|
||||||
|
// SIMD functions
|
||||||
|
static void ref_function(const int16_t *filter, int filterSize,
|
||||||
|
const int16_t **src, uint8_t *dest, int dstW,
|
||||||
|
const uint8_t *dither, int offset)
|
||||||
|
{
|
||||||
|
int i, d;
|
||||||
|
d = ((filterSize - 1) * 8 + dither[0]) >> 4;
|
||||||
|
for ( i = 0; i < dstW; i++) {
|
||||||
|
int16_t val = d;
|
||||||
|
int j;
|
||||||
|
union {
|
||||||
|
int val;
|
||||||
|
int16_t v[2];
|
||||||
|
} t;
|
||||||
|
for (j = 0; j < filterSize; j++){
|
||||||
|
t.val = (int)src[j][i + offset] * (int)filter[j];
|
||||||
|
val += t.v[1];
|
||||||
|
}
|
||||||
|
dest[i]= av_clip_uint8(val>>3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_yuv2yuvX(void)
|
||||||
|
{
|
||||||
|
struct SwsContext *ctx;
|
||||||
|
int fsi, osi, isi, i, j;
|
||||||
|
int dstW;
|
||||||
|
#define LARGEST_FILTER 16
|
||||||
|
#define FILTER_SIZES 4
|
||||||
|
static const int filter_sizes[FILTER_SIZES] = {1, 4, 8, 16};
|
||||||
|
#define LARGEST_INPUT_SIZE 512
|
||||||
|
#define INPUT_SIZES 4
|
||||||
|
static const int input_sizes[INPUT_SIZES] = {128, 144, 256, 512};
|
||||||
|
|
||||||
|
declare_func_emms(AV_CPU_FLAG_MMX, void, const int16_t *filter,
|
||||||
|
int filterSize, const int16_t **src, uint8_t *dest,
|
||||||
|
int dstW, const uint8_t *dither, int offset);
|
||||||
|
|
||||||
|
const int16_t **src;
|
||||||
|
LOCAL_ALIGNED_8(int16_t, src_pixels, [LARGEST_FILTER * LARGEST_INPUT_SIZE]);
|
||||||
|
LOCAL_ALIGNED_8(int16_t, filter_coeff, [LARGEST_FILTER]);
|
||||||
|
LOCAL_ALIGNED_8(uint8_t, dst0, [LARGEST_INPUT_SIZE]);
|
||||||
|
LOCAL_ALIGNED_8(uint8_t, dst1, [LARGEST_INPUT_SIZE]);
|
||||||
|
LOCAL_ALIGNED_8(uint8_t, dither, [LARGEST_INPUT_SIZE]);
|
||||||
|
union VFilterData{
|
||||||
|
const int16_t *src;
|
||||||
|
uint16_t coeff[8];
|
||||||
|
} *vFilterData;
|
||||||
|
uint8_t d_val = rnd();
|
||||||
|
randomize_buffers(filter_coeff, LARGEST_FILTER);
|
||||||
|
randomize_buffers(src_pixels, LARGEST_FILTER * LARGEST_INPUT_SIZE);
|
||||||
|
ctx = sws_alloc_context();
|
||||||
|
if (sws_init_context(ctx, NULL, NULL) < 0)
|
||||||
|
fail();
|
||||||
|
|
||||||
|
ff_getSwsFunc(ctx);
|
||||||
|
for(i = 0; i < LARGEST_INPUT_SIZE; ++i){
|
||||||
|
dither[i] = d_val;
|
||||||
|
}
|
||||||
|
for(isi = 0; isi < INPUT_SIZES; ++isi){
|
||||||
|
dstW = input_sizes[isi];
|
||||||
|
for(osi = 0; osi < 64; osi += 16){
|
||||||
|
for(fsi = 0; fsi < FILTER_SIZES; ++fsi){
|
||||||
|
src = av_malloc(sizeof(int16_t*) * filter_sizes[fsi]);
|
||||||
|
vFilterData = av_malloc((filter_sizes[fsi] + 2) * sizeof(union VFilterData));
|
||||||
|
memset(vFilterData, 0, (filter_sizes[fsi] + 2) * sizeof(union VFilterData));
|
||||||
|
for(i = 0; i < filter_sizes[fsi]; ++i){
|
||||||
|
src[i] = &src_pixels[i * LARGEST_INPUT_SIZE];
|
||||||
|
vFilterData[i].src = src[i];
|
||||||
|
for(j = 0; j < 4; ++j)
|
||||||
|
vFilterData[i].coeff[j + 4] = filter_coeff[i];
|
||||||
|
}
|
||||||
|
if (check_func(ctx->yuv2planeX, "yuv2yuvX_%d_%d", filter_sizes[fsi], osi)){
|
||||||
|
memset(dst0, 0, LARGEST_INPUT_SIZE * sizeof(dst0[0]));
|
||||||
|
memset(dst1, 0, LARGEST_INPUT_SIZE * sizeof(dst1[0]));
|
||||||
|
|
||||||
|
// The reference function is not the scalar function selected when mmx
|
||||||
|
// is deactivated as the SIMD functions do not give the same result as
|
||||||
|
// the scalar ones due to rounding. The SIMD functions are activated by
|
||||||
|
// the flag SWS_ACCURATE_RND
|
||||||
|
ref_function(&filter_coeff[0], filter_sizes[fsi], src, dst0, dstW - osi, dither, osi);
|
||||||
|
// There's no point in calling new for the reference function
|
||||||
|
if(ctx->use_mmx_vfilter){
|
||||||
|
call_new((const int16_t*)vFilterData, filter_sizes[fsi], src, dst1, dstW - osi, dither, osi);
|
||||||
|
if (memcmp(dst0, dst1, LARGEST_INPUT_SIZE * sizeof(dst0[0])))
|
||||||
|
fail();
|
||||||
|
if(dstW == LARGEST_INPUT_SIZE)
|
||||||
|
bench_new((const int16_t*)vFilterData, filter_sizes[fsi], src, dst1, dstW - osi, dither, osi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(src);
|
||||||
|
free(vFilterData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sws_freeContext(ctx);
|
||||||
|
#undef FILTER_SIZES
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SRC_PIXELS
|
||||||
#define SRC_PIXELS 128
|
#define SRC_PIXELS 128
|
||||||
|
|
||||||
static void check_hscale(void)
|
static void check_hscale(void)
|
||||||
@ -132,4 +233,6 @@ void checkasm_check_sw_scale(void)
|
|||||||
{
|
{
|
||||||
check_hscale();
|
check_hscale();
|
||||||
report("hscale");
|
report("hscale");
|
||||||
|
check_yuv2yuvX();
|
||||||
|
report("yuv2yuvX");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user